diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-26 10:57:01 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-26 10:57:01 +0000 |
commit | f35ebe9caf290b8266faae05f7ab8491ad301d7a (patch) | |
tree | 39d39e6eac3dd73663d172228b40ec9bc2709301 /app/ssh-askpass/x11-ssh-askpass.c | |
parent | 1cb4778bcef21ea9015cfccdb99abb7a0e035d74 (diff) |
Importing from XF4, plus BSD make infrastructure
Diffstat (limited to 'app/ssh-askpass/x11-ssh-askpass.c')
-rw-r--r-- | app/ssh-askpass/x11-ssh-askpass.c | 1551 |
1 files changed, 1551 insertions, 0 deletions
diff --git a/app/ssh-askpass/x11-ssh-askpass.c b/app/ssh-askpass/x11-ssh-askpass.c new file mode 100644 index 000000000..48f882ae2 --- /dev/null +++ b/app/ssh-askpass/x11-ssh-askpass.c @@ -0,0 +1,1551 @@ +/* x11-ssh-askpass.c: A generic X11-based password dialog for OpenSSH. + * created 1999-Nov-17 03:40 Jim Knoble <jmknoble@jmknoble.cx> + * autodate: 2001-Feb-14 04:00 + * + * by Jim Knoble <jmknoble@jmknoble.cx> + * Copyright (C) 1999,2000,2001 Jim Knoble + * + * Disclaimer: + * + * The software is provided "as is", without warranty of any kind, + * express or implied, including but not limited to the warranties of + * merchantability, fitness for a particular purpose and + * noninfringement. In no event shall the author(s) be liable for any + * claim, damages or other liability, whether in an action of + * contract, tort or otherwise, arising from, out of or in connection + * with the software or the use or other dealings in the software. + * + * Portions of this code are distantly derived from code in xscreensaver + * by Jamie Zawinski <jwz@jwz.org>. That code says: + * + * --------8<------------------------------------------------8<-------- + * xscreensaver, Copyright (c) 1991-1999 Jamie Zawinski <jwz@jwz.org> + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * --------8<------------------------------------------------8<-------- + * + * The remainder of this code falls under the same permissions and + * provisions as those of the xscreensaver code. + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* For (get|set)rlimit() ... */ +#include <sys/time.h> +#include <sys/resource.h> +/* ... end */ +/* For (get|set)rlimit(), sleep(), and getpid() ... */ +#include <unistd.h> +/* ... end */ + +/* For errno ... */ +#include <errno.h> +/* ... end */ + +#include <X11/Xlib.h> +#include <X11/Intrinsic.h> +#include <X11/Shell.h> +#include <X11/Xos.h> +#include "dynlist.h" +#include "drawing.h" +#include "resources.h" +#include "x11-ssh-askpass.h" + +#undef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +char *progname = NULL; +char *progclass = NULL; +XrmDatabase db = 0; + +static char *defaults[] = { +#include "SshAskpass_ad.h" + 0 +}; + +void outOfMemory(AppInfo *app, int line) +{ + fprintf(stderr, "%s[%ld]: Aaahhh! I ran out of memory at line %d.\n", + app->appName, (long) app->pid, line); + exit(EXIT_STATUS_NO_MEMORY); +} + +void freeIf(void *p) +{ + if (p) { + free(p); + } +} + +void freeFontIf(AppInfo *app, XFontStruct *f) +{ + if (f) { + XFreeFont(app->dpy, f); + } +} + +XFontStruct *getFontResource(AppInfo *app, char *instanceName, char *className) +{ + char *fallbackFont = "fixed"; + + XFontStruct *f = NULL; + char *s = get_string_resource(instanceName, className); + f = XLoadQueryFont(app->dpy, (s ? s : fallbackFont)); + if (!f) { + f = XLoadQueryFont(app->dpy, fallbackFont); + } + if (s) { + free(s); + } + return(f); +} + +char *getStringResourceWithDefault(char *instanceName, char *className, + char *defaultText) +{ + char *s = get_string_resource(instanceName, className); + if (!s) { + if (!defaultText) { + s = strdup(""); + } else { + s = strdup(defaultText); + } + } + return(s); +} + +unsigned int getUnsignedIntegerResource(AppInfo *app, char *instanceName, + char *className, + unsigned int defaultValue) +{ + int n; + unsigned int value; + char c; + char *s = get_string_resource(instanceName, className); + char *cp = s; + + if (NULL == s) { + return(defaultValue); + } + while ((*cp) && isspace(*cp)) { + /* Skip whitespace. */ + cp++; + } + if (*cp) { + if (('0' == cp[0]) && cp[1]) { + if (('x' == cp[1]) || ('X' == cp[1])) { + /* Hex */ + n = sscanf(cp + 2, "%x %c", &value, &c); + } else { + /* Octal */ + n = sscanf(cp + 1, "%o %c", &value, &c); + } + if (1 == n) { + free(s); + return(value); + } + } else { + /* Unsigned Decimal */ + n = sscanf(cp, "%u %c", &value, &c); + if (1 == n) { + free(s); + return(value); + } + } + } + /* If we get here, no conversion succeeded. */ + fprintf(stderr, "%s[%ld]: invalid value '%s' for %s.\n", + app->appName, (long) app->pid, s, instanceName); + free(s); + return(defaultValue); +} + +/* Default resolution is 75 dots/inch. 1 in = 2.54 cm. */ +#define DefaultResolution ((75 * 10000) / 254) +long getResolutionResource(AppInfo *app, char *instanceName, char *className, + char *defaultResolutionSpec) +{ + char units[3]; + char *s; + int n; + long resolution; + unsigned int i; + + memset(units, 0, sizeof(units)); + s = getStringResourceWithDefault(instanceName, className, + defaultResolutionSpec); + /* NOTE: The width of the %s format must be one less than + * the length of the units[] array above! + */ + n = sscanf(s, "%ld / %2s", &resolution, units); + if (n != 2) { + fprintf(stderr, "%s[%ld]: invalid value '%s' for %s.\n", + app->appName, (long) app->pid, s, instanceName); + resolution = DefaultResolution; + } else { + if (resolution < 0) { + /* Resolution specifications should not be negative. */ + resolution = -(resolution); + } + for (i = 0; i < (sizeof(units) - 1); i++) { + units[i] = tolower(units[i]); + } + if ((0 == strcmp(units, "in")) || + (0 == strcmp(units, "i")) || + (0 == strcmp(units, "\""))) { + /* dots/inch */ + resolution = resolution * 10000 / 254; + } else if ((0 == strcmp(units, "m")) || + (0 == strcmp(units, "me"))) { + /* dots/meter; no conversion necessary */ + ; + } else { + /* some unit we don't recognize; cringe and stare at the floor */ + resolution = DefaultResolution; + } + } + return(resolution); +} +#undef DefaultResolution + +void calcTextObjectExtents(TextObject *t, XFontStruct *font) { + if ((!t) || (!(t->text))) { + return; + } + t->textLength = strlen(t->text); + XTextExtents(font, t->text, t->textLength, &(t->direction), + &(t->ascent), &(t->descent), &(t->overall)); +} + +void calcLabelTextExtents(LabelInfo *label) +{ + TextObject *t; + + if ((!label) || (!(label->fullText)) || (!(label->font))) { + return; + } + t = label->multiText; + while (NULL != t) { + calcTextObjectExtents(t, label->font); + label->w.height += (t->ascent + t->descent); + if (label->w.width < t->overall.width) { + label->w.width = t->overall.width; + } + t = t->next; + } +} + +void calcTotalButtonExtents(ButtonInfo *button) +{ + if (!button) { + return; + } + button->w3.w.width = (button->w3.interiorWidth + + (2 * button->w3.shadowThickness)); + button->w3.w.width += (2 * button->w3.borderWidth); + button->w3.w.height = (button->w3.interiorHeight + + (2 * button->w3.shadowThickness)); + button->w3.w.height += (2 * button->w3.borderWidth); +} + +void calcButtonExtents(ButtonInfo *button) +{ + if (!button) { + return; + } + calcLabelTextExtents(&(button->label)); + button->w3.interiorWidth = (button->label.w.width + + (2 * button->w3.horizontalSpacing)); + button->w3.interiorHeight = (button->label.w.height + + (2 * button->w3.verticalSpacing)); + calcTotalButtonExtents(button); +} + +void balanceButtonExtents(ButtonInfo *button1, ButtonInfo *button2) +{ + if ((!button1) || (!button2)) { + return; + } + button1->w3.interiorWidth = button2->w3.interiorWidth = + MAX(button1->w3.interiorWidth, button2->w3.interiorWidth); + button1->w3.interiorHeight = button2->w3.interiorHeight = + MAX(button1->w3.interiorHeight, button2->w3.interiorHeight); + calcTotalButtonExtents(button1); + calcTotalButtonExtents(button2); +} + +void calcButtonLabelPosition(ButtonInfo *button) +{ + if (!button) { + return; + } + button->label.w.x = button->w3.w.x + + ((button->w3.w.width - button->label.w.width) / 2); + button->label.w.y = button->w3.w.y + + ((button->w3.w.height - button->label.w.height) / 2); +} + +Dimension scaleXDimension(AppInfo *app, Dimension unscaled) +{ + Dimension scaled; + + if (((app->defaultXResolution < app->xResolution) && + ((app->defaultXResolution + app->xFuzz) < app->xResolution)) || + ((app->xResolution < app->defaultXResolution) && + ((app->xResolution + app->xFuzz) < app->defaultXResolution))) { + scaled = (unscaled * app->xResolution) / app->defaultXResolution; + } else { + scaled = unscaled; + } + return(scaled); +} + +Dimension scaleYDimension(AppInfo *app, Dimension unscaled) +{ + Dimension scaled; + + if (((app->defaultYResolution < app->yResolution) && + ((app->defaultYResolution + app->yFuzz) < app->yResolution)) || + ((app->yResolution < app->defaultYResolution) && + ((app->yResolution + app->yFuzz) < app->defaultYResolution))) { + scaled = (unscaled * app->yResolution) / app->defaultYResolution; + } else { + scaled = unscaled; + } + return(scaled); +} + +/* Assumes 's' is non-NULL. */ +TextObject *createTextObject(AppInfo *app, char *s) +{ + TextObject *t = malloc(sizeof(*t)); + if (NULL == t) { + outOfMemory(app, __LINE__); + } + memset(t, 0, sizeof(*t)); + if (('\n' == *s) || ('\0' == *s)) { + t->text = " "; + } else { + t->text = s; + } + return(t); +} + +/* Assumes 'label' object exists and is zeroed. */ +void createLabel(AppInfo *app, char *text, LabelInfo *label) +{ + char *substring; + TextObject *t; + + if ((!app) || (!text)) { + return; + } + label->fullText = strdup(text); + label->multiText = createTextObject(app, label->fullText); + t = label->multiText; + substring = strchr(label->fullText, '\n'); + while (NULL != substring) { + *(substring++) = '\0'; + t->next = createTextObject(app, substring); + if (t->next) { + t = t->next; + } + substring = strchr(substring, '\n'); + } +} + +void createDialog(AppInfo *app) +{ + DialogInfo *d; + char *labelText; + + if (app->dialog) { + return; + } + d = malloc(sizeof(*d)); + if (NULL == d) { + outOfMemory(app, __LINE__); + } + memset(d, 0, sizeof(*d)); + + app->grabKeyboard = + get_boolean_resource("grabKeyboard", "GrabKeyboard", True); + app->grabPointer = + get_boolean_resource("grabPointer", "GrabPointer", False); + app->grabServer = + get_boolean_resource("grabServer", "GrabServer", False); + + /* inputTimeout resource specified in seconds for easy human interface. + * Convert to milliseconds here. + */ + app->inputTimeout = (unsigned long) 1000 * + getUnsignedIntegerResource(app, "inputTimeout", "InputTimeout", 0); + + app->defaultXResolution = + getResolutionResource(app, "defaultXResolution", "DefaultXResolution", + "75/in"); + app->defaultYResolution = + getResolutionResource(app, "defaultYResolution", "DefaultYResolution", + "75/in"); + app->xFuzz = + getResolutionResource(app, "xResolutionFuzz", "XResolutionFuzz", "20/in"); + app->yFuzz = + getResolutionResource(app, "yResolutionFuzz", "YResolutionFuzz", "20/in"); + + d->title = + getStringResourceWithDefault("dialog.title", "Dialog.Title", + "OpenSSH Authentication Passphrase Request"); + d->w3.w.foreground = + get_pixel_resource("foreground", "Foreground", + app->dpy, app->colormap, app->black); + d->w3.w.background = + get_pixel_resource("background", "Background", + app->dpy, app->colormap, app->white); + d->w3.topShadowColor = + get_pixel_resource("topShadowColor", "TopShadowColor", + app->dpy, app->colormap, app->white); + d->w3.bottomShadowColor = + get_pixel_resource("bottomShadowColor", "BottomShadowColor", + app->dpy, app->colormap, app->black); + d->w3.shadowThickness = + get_integer_resource("shadowThickness", "ShadowThickness", 3); + d->w3.borderColor = + get_pixel_resource("borderColor", "BorderColor", + app->dpy, app->colormap, app->black); + d->w3.borderWidth = + get_integer_resource("borderWidth", "BorderWidth", 1); + + d->w3.horizontalSpacing = scaleXDimension(app, + get_integer_resource("horizontalSpacing", "Spacing", 5)); + d->w3.verticalSpacing = scaleYDimension(app, + get_integer_resource("verticalSpacing", "Spacing", 6)); + + if (2 == app->argc) { + labelText = strdup(app->argv[1]); + } else { + labelText = + getStringResourceWithDefault("dialog.label", "Dialog.Label", + "Please enter your authentication passphrase:"); + } + createLabel(app, labelText, &(d->label)); + freeIf(labelText); + d->label.font = getFontResource(app, "dialog.font", "Dialog.Font"); + calcLabelTextExtents(&(d->label)); + d->label.w.foreground = d->w3.w.foreground; + d->label.w.background = d->w3.w.background; + + d->okButton.w3.w.foreground = + get_pixel_resource("okButton.foreground", "Button.Foreground", + app->dpy, app->colormap, app->black); + d->okButton.w3.w.background = + get_pixel_resource("okButton.background", "Button.Background", + app->dpy, app->colormap, app->white); + d->okButton.w3.topShadowColor = + get_pixel_resource("okButton.topShadowColor", "Button.TopShadowColor", + app->dpy, app->colormap, app->white); + d->okButton.w3.bottomShadowColor = + get_pixel_resource("okButton.bottomShadowColor", + "Button.BottomShadowColor", + app->dpy, app->colormap, app->black); + d->okButton.w3.shadowThickness = + get_integer_resource("okButton.shadowThickness", + "Button.ShadowThickness", 2); + d->okButton.w3.borderColor = + get_pixel_resource("okButton.borderColor", "Button.BorderColor", + app->dpy, app->colormap, app->black); + d->okButton.w3.borderWidth = + get_integer_resource("okButton.borderWidth", "Button.BorderWidth", 1); + d->okButton.w3.horizontalSpacing = scaleXDimension(app, + get_integer_resource("okButton.horizontalSpacing", "Button.Spacing", 4)); + d->okButton.w3.verticalSpacing = scaleYDimension(app, + get_integer_resource("okButton.verticalSpacing", "Button.Spacing", 2)); + labelText = + getStringResourceWithDefault("okButton.label", "Button.Label", "OK"); + createLabel(app, labelText, &(d->okButton.label)); + freeIf(labelText); + d->okButton.label.font = + getFontResource(app, "okButton.font", "Button.Font"); + calcButtonExtents(&(d->okButton)); + d->okButton.label.w.foreground = d->okButton.w3.w.foreground; + d->okButton.label.w.background = d->okButton.w3.w.background; + + d->cancelButton.w3.w.foreground = + get_pixel_resource("cancelButton.foreground", "Button.Foreground", + app->dpy, app->colormap, app->black); + d->cancelButton.w3.w.background = + get_pixel_resource("cancelButton.background", "Button.Background", + app->dpy, app->colormap, app->white); + d->cancelButton.w3.topShadowColor = + get_pixel_resource("cancelButton.topShadowColor", + "Button.TopShadowColor", + app->dpy, app->colormap, app->white); + d->cancelButton.w3.bottomShadowColor = + get_pixel_resource("cancelButton.bottomShadowColor", + "Button.BottomShadowColor", + app->dpy, app->colormap, app->black); + d->cancelButton.w3.shadowThickness = + get_integer_resource("cancelButton.shadowThickness", + "Button.ShadowThickness", 2); + d->cancelButton.w3.borderColor = + get_pixel_resource("cancelButton.borderColor", "Button.BorderColor", + app->dpy, app->colormap, app->black); + d->cancelButton.w3.borderWidth = + get_integer_resource("cancelButton.borderWidth", "Button.BorderWidth", + 1); + d->cancelButton.w3.horizontalSpacing = scaleXDimension(app, + get_integer_resource("cancelButton.horizontalSpacing", "Button.Spacing", + 4)); + d->cancelButton.w3.verticalSpacing = scaleYDimension(app, + get_integer_resource("cancelButton.verticalSpacing", "Button.Spacing", + 2)); + labelText = + getStringResourceWithDefault("cancelButton.label", "Button.Label", + "Cancel"); + createLabel(app, labelText, &(d->cancelButton.label)); + freeIf(labelText); + d->cancelButton.label.font = + getFontResource(app, "cancelButton.font", "Button.Font"); + calcButtonExtents(&(d->cancelButton)); + d->cancelButton.label.w.foreground = d->cancelButton.w3.w.foreground; + d->cancelButton.label.w.background = d->cancelButton.w3.w.background; + + balanceButtonExtents(&(d->okButton), &(d->cancelButton)); + + d->indicator.w3.w.foreground = + get_pixel_resource("indicator.foreground", "Indicator.Foreground", + app->dpy, app->colormap, app->black); + d->indicator.w3.w.background = + get_pixel_resource("indicator.background", "Indicator.Background", + app->dpy, app->colormap, app->white); + d->indicator.w3.w.width = scaleXDimension(app, + get_integer_resource("indicator.width", "Indicator.Width", 15)); + d->indicator.w3.w.height = scaleYDimension(app, + get_integer_resource("indicator.height", "Indicator.Height", 7)); + d->indicator.w3.topShadowColor = + get_pixel_resource("indicator.topShadowColor", + "Indicator.TopShadowColor", + app->dpy, app->colormap, app->white); + d->indicator.w3.bottomShadowColor = + get_pixel_resource("indicator.bottomShadowColor", + "Indicator.BottomShadowColor", + app->dpy, app->colormap, app->black); + d->indicator.w3.shadowThickness = + get_integer_resource("indicator.shadowThickness", + "Indicator.ShadowThickness", 2); + d->indicator.w3.borderColor = + get_pixel_resource("indicator.borderColor", "Indicator.BorderColor", + app->dpy, app->colormap, app->black); + d->indicator.w3.borderWidth = + get_integer_resource("indicator.borderWidth", "Indicator.BorderWidth", + 0); + d->indicator.w3.horizontalSpacing = scaleXDimension(app, + get_integer_resource("indicator.horizontalSpacing", "Indicator.Spacing", + 2)); + d->indicator.w3.verticalSpacing =scaleYDimension(app, + get_integer_resource("indicator.verticalSpacing", "Indicator.Spacing", + 4)); + d->indicator.minimumCount = + get_integer_resource("indicator.minimumCount", "Indicator.MinimumCount", + 8); + d->indicator.maximumCount = + get_integer_resource("indicator.maximumCount", "Indicator.MaximumCount", + 24); + d->indicator.w3.interiorWidth = d->indicator.w3.w.width; + d->indicator.w3.interiorHeight = d->indicator.w3.w.height; + d->indicator.w3.w.width += (2 * d->indicator.w3.shadowThickness); + d->indicator.w3.w.width += (2 * d->indicator.w3.borderWidth); + d->indicator.w3.w.height += (2 * d->indicator.w3.shadowThickness); + d->indicator.w3.w.height += (2 * d->indicator.w3.borderWidth); + { + /* Make sure the indicators can all fit on the screen. + * 80% of the screen width seems fine. + */ + Dimension maxWidth = (WidthOfScreen(app->screen) * 8 / 10); + Dimension extraSpace = ((2 * d->w3.horizontalSpacing) + + (2 * d->w3.shadowThickness)); + + if (d->indicator.maximumCount < 8) { + d->indicator.maximumCount = 8; + } + if (((d->indicator.maximumCount * d->indicator.w3.w.width) + + ((d->indicator.maximumCount - 1) * + d->indicator.w3.horizontalSpacing) + extraSpace) > maxWidth) { + d->indicator.maximumCount = + ((maxWidth - extraSpace - d->indicator.w3.w.width) / + (d->indicator.w3.w.width + d->indicator.w3.horizontalSpacing)) + + 1; + } + if (d->indicator.minimumCount <= 6) { + d->indicator.minimumCount = 6; + } + if (d->indicator.minimumCount > d->indicator.maximumCount) { + d->indicator.minimumCount = d->indicator.maximumCount; + } + } + + { + /* Calculate the width and horizontal position of things. */ + Dimension labelAreaWidth; + Dimension buttonAreaWidth; + Dimension indicatorAreaWidth; + Dimension extraIndicatorSpace; + Dimension singleIndicatorSpace; + Dimension interButtonSpace; + Dimension w; + Position leftX; + int i; + + labelAreaWidth = d->label.w.width + (2 * d->w3.horizontalSpacing); + buttonAreaWidth = ((3 * d->w3.horizontalSpacing) + + d->okButton.w3.w.width + + d->cancelButton.w3.w.width); + w = MAX(labelAreaWidth, buttonAreaWidth); + extraIndicatorSpace = ((2 * d->w3.horizontalSpacing) + + d->indicator.w3.w.width); + singleIndicatorSpace = (d->indicator.w3.w.width + + d->indicator.w3.horizontalSpacing); + d->indicator.count = ((w - extraIndicatorSpace) / singleIndicatorSpace); + d->indicator.current = 0; + d->indicator.count++; /* For gatepost indicator in extra space. */ + if (((w - extraIndicatorSpace) % singleIndicatorSpace) > + (singleIndicatorSpace / 2)) { + d->indicator.count++; + } + if (d->indicator.count < d->indicator.minimumCount) { + d->indicator.count = d->indicator.minimumCount; + } + if (d->indicator.count > d->indicator.maximumCount) { + d->indicator.count = d->indicator.maximumCount; + } + indicatorAreaWidth = ((singleIndicatorSpace * (d->indicator.count - 1)) + + extraIndicatorSpace); + d->w3.interiorWidth = MAX(w, indicatorAreaWidth); + d->w3.w.width = d->w3.interiorWidth + (2 * d->w3.shadowThickness); + + leftX = (d->w3.w.width - d->label.w.width) / 2; + d->label.w.x = leftX; + + leftX = ((d->w3.w.width - + (d->indicator.count * d->indicator.w3.w.width) - + ((d->indicator.count - 1) * d->indicator.w3.horizontalSpacing)) + / 2); + { + int n = d->indicator.count * sizeof(IndicatorElement); + d->indicators = malloc(n); + if (NULL == d->indicators) { + destroyDialog(app); + outOfMemory(app, __LINE__); + } + memset(d->indicators, 0, n); + } + d->indicators[0].parent = &(d->indicator); + d->indicators[0].w.x = d->indicator.w3.w.x = leftX; + d->indicators[0].w.width = d->indicator.w3.w.width; + d->indicators[0].isLit = False; + for (i = 1; i < d->indicator.count; i++) { + d->indicators[i].parent = &(d->indicator); + d->indicators[i].w.x = (d->indicators[i - 1].w.x + + d->indicator.w3.w.width + + d->indicator.w3.horizontalSpacing); + d->indicators[i].w.width = d->indicator.w3.w.width; + d->indicators[i].isLit = False; + } + interButtonSpace = ((d->w3.interiorWidth - d->okButton.w3.w.width - + d->cancelButton.w3.w.width) / 3); + d->okButton.w3.w.x = interButtonSpace + d->w3.shadowThickness; + d->cancelButton.w3.w.x = (d->okButton.w3.w.x + d->okButton.w3.w.width + + interButtonSpace); + } + { + /* Calculate the height and vertical position of things. */ + int i; + + d->w3.interiorHeight = ((4 * d->w3.verticalSpacing) + + (2 * d->indicator.w3.verticalSpacing) + + d->label.w.height + + d->indicator.w3.w.height + + d->okButton.w3.w.height); + d->w3.w.height = d->w3.interiorHeight + (2 * d->w3.shadowThickness); + d->label.w.y = d->w3.shadowThickness + d->w3.verticalSpacing; + d->indicator.w3.w.y = (d->label.w.y + d->label.w.height + + d->w3.verticalSpacing + + d->indicator.w3.verticalSpacing); + for (i = 0; i < d->indicator.count; i++) { + d->indicators[i].w.y = d->indicator.w3.w.y; + d->indicators[i].w.height = d->indicator.w3.w.height; + } + d->okButton.w3.w.y = d->cancelButton.w3.w.y = + (d->indicator.w3.w.y + d->indicator.w3.w.height + + d->w3.verticalSpacing + d->indicator.w3.verticalSpacing); + } + calcButtonLabelPosition(&(d->okButton)); + calcButtonLabelPosition(&(d->cancelButton)); + + d->w3.w.x = (WidthOfScreen(app->screen) - d->w3.w.width) / 2; + d->w3.w.y = (HeightOfScreen(app->screen) - d->w3.w.height) / 3; + + app->dialog = d; +} + +void destroyLabel(AppInfo *app, LabelInfo *label) +{ + TextObject *thisTextObject; + TextObject *nextTextObject; + + thisTextObject = label->multiText; + nextTextObject = thisTextObject->next; + freeIf(thisTextObject); + while (NULL != nextTextObject) { + thisTextObject = nextTextObject; + nextTextObject = thisTextObject->next; + freeIf(thisTextObject); + } + freeIf(label->fullText); + freeFontIf(app, label->font); +} + +void destroyDialog(AppInfo *app) +{ + DialogInfo *d = app->dialog; + + freeIf(d->title); + freeIf(d->indicators); + + destroyLabel(app, &(d->label)); + destroyLabel(app, &(d->okButton.label)); + destroyLabel(app, &(d->cancelButton.label)); + + XFree(d->sizeHints); + XFree(d->wmHints); + XFree(d->classHints); + XFree(d->windowName.value); + + freeIf(d); +} + +void createDialogWindow(AppInfo *app) +{ + XSetWindowAttributes attr; + unsigned long attrMask = 0; + DialogInfo *d = app->dialog; + + attr.background_pixel = d->w3.w.background; + attrMask |= CWBackPixel; + attr.border_pixel = d->w3.borderColor; + attrMask |= CWBorderPixel; + attr.cursor = None; + attrMask |= CWCursor; + attr.event_mask = app->eventMask; + attrMask |= CWEventMask; + + d->dialogWindow = XCreateWindow(app->dpy, app->rootWindow, + d->w3.w.x, d->w3.w.y, + d->w3.w.width, d->w3.w.height, + d->w3.borderWidth, + DefaultDepthOfScreen(app->screen), + InputOutput, + DefaultVisualOfScreen(app->screen), + attrMask, &attr); + + d->sizeHints = XAllocSizeHints(); + if (!(d->sizeHints)) { + destroyDialog(app); + outOfMemory(app, __LINE__); + } + d->sizeHints->flags = 0; + d->sizeHints->flags |= PPosition; + d->sizeHints->flags |= PSize; + d->sizeHints->min_width = d->w3.w.width; + d->sizeHints->min_height = d->w3.w.height; + d->sizeHints->flags |= PMinSize; + d->sizeHints->max_width = d->w3.w.width; + d->sizeHints->max_height = d->w3.w.height; + d->sizeHints->flags |= PMaxSize; + d->sizeHints->base_width = d->w3.w.width; + d->sizeHints->base_height = d->w3.w.height; + d->sizeHints->flags |= PBaseSize; + + d->wmHints = XAllocWMHints(); + if (!(d->wmHints)) { + destroyDialog(app); + outOfMemory(app, __LINE__); + } + d->wmHints->flags = 0; + d->wmHints->input = True; + d->wmHints->flags |= InputHint; + d->wmHints->initial_state = NormalState; + d->wmHints->flags |= StateHint; + + d->classHints = XAllocClassHint(); + if (!(d->classHints)) { + destroyDialog(app); + outOfMemory(app, __LINE__); + } + d->classHints->res_name = app->appName; + d->classHints->res_class = app->appClass; + + if (!XStringListToTextProperty(&(d->title), 1, &(d->windowName))) { + destroyDialog(app); + outOfMemory(app, __LINE__); + } + XSetWMProperties(app->dpy, d->dialogWindow, &(d->windowName), NULL, + app->argv, app->argc, d->sizeHints, + d->wmHints, d->classHints); + XSetTransientForHint(app->dpy, d->dialogWindow, d->dialogWindow); + + app->wmDeleteWindowAtom = XInternAtom(app->dpy, "WM_DELETE_WINDOW", False); + XSetWMProtocols(app->dpy, d->dialogWindow, &(app->wmDeleteWindowAtom), 1); +} + +void createGCs(AppInfo *app) +{ + DialogInfo *d = app->dialog; + + XGCValues gcv; + unsigned long gcvMask; + + gcvMask = 0; + gcv.foreground = d->w3.w.background; + gcvMask |= GCForeground; + gcv.fill_style = FillSolid; + gcvMask |= GCFillStyle; + app->fillGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); + + gcvMask = 0; + gcv.foreground = d->w3.borderColor; + gcvMask |= GCForeground; + gcv.line_width = d->w3.borderWidth; + gcvMask |= GCLineWidth; + gcv.line_style = LineSolid; + gcvMask |= GCLineStyle; + gcv.cap_style = CapButt; + gcvMask |= GCCapStyle; + gcv.join_style = JoinMiter; + gcvMask |= GCJoinStyle; + app->borderGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); + + gcvMask = 0; + gcv.foreground = d->label.w.foreground; + gcvMask |= GCForeground; + gcv.background = d->label.w.background; + gcvMask |= GCBackground; + gcv.font = d->label.font->fid; + gcvMask |= GCFont; + app->textGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); + + gcvMask = 0; + gcv.foreground = d->indicator.w3.w.foreground; + gcvMask |= GCForeground; + gcv.fill_style = FillSolid; + gcvMask |= GCFillStyle; + app->brightGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); + + gcvMask = 0; + gcv.foreground = d->indicator.w3.w.background; + gcvMask |= GCForeground; + gcv.fill_style = FillSolid; + gcvMask |= GCFillStyle; + app->dimGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); +} + +void destroyGCs(AppInfo *app) +{ + XFreeGC(app->dpy, app->fillGC); + XFreeGC(app->dpy, app->borderGC); + XFreeGC(app->dpy, app->textGC); + XFreeGC(app->dpy, app->brightGC); + XFreeGC(app->dpy, app->dimGC); +} + +void paintLabel(AppInfo *app, Drawable draw, LabelInfo label) +{ + TextObject *t; + Position x; + Position y; + + if (!(label.fullText)) { + return; + } + XSetForeground(app->dpy, app->textGC, label.w.foreground); + XSetBackground(app->dpy, app->textGC, label.w.background); + XSetFont(app->dpy, app->textGC, label.font->fid); + + t = label.multiText; + x = label.w.x; + y = label.w.y + t->ascent; + while (NULL != t) { + if (t->text) { + XDrawString(app->dpy, draw, app->textGC, x, y, t->text, + t->textLength); + } + y += t->descent; + t = t->next; + if (t) { + y += t->ascent; + } + } +} + +void paintButton(AppInfo *app, Drawable draw, ButtonInfo button) +{ + Position x; + Position y; + Dimension width; + Dimension height; + + if (button.w3.borderWidth > 0) { + XSetForeground(app->dpy, app->borderGC, button.w3.borderColor); + XFillRectangle(app->dpy, draw, app->borderGC, button.w3.w.x, + button.w3.w.y, button.w3.w.width, button.w3.w.height); + } + if ((button.w3.shadowThickness <= 0) && (button.pressed)) { + Pixel tmp = button.w3.w.background; + button.w3.w.background = button.w3.w.foreground; + button.w3.w.foreground = tmp; + tmp = button.label.w.background; + button.label.w.background = button.label.w.foreground; + button.label.w.foreground = tmp; + } + x = (button.w3.w.x + button.w3.borderWidth); + y = (button.w3.w.y + button.w3.borderWidth); + width = (button.w3.w.width - (2 * button.w3.borderWidth)); + height = (button.w3.w.height - (2 * button.w3.borderWidth)); + if ((button.w3.shadowThickness > 0) && (button.pressed)) { + XSetForeground(app->dpy, app->fillGC, button.w3.topShadowColor); + } else { + XSetForeground(app->dpy, app->fillGC, button.w3.w.background); + } + XFillRectangle(app->dpy, draw, app->fillGC, x, y, width, height); + if (button.w3.shadowThickness > 0) { + if (button.pressed) { + draw_shaded_rectangle(app->dpy, draw, x, y, width, height, + button.w3.shadowThickness, + button.w3.bottomShadowColor, + button.w3.topShadowColor); + } else { + draw_shaded_rectangle(app->dpy, draw, x, y, width, height, + button.w3.shadowThickness, + button.w3.topShadowColor, + button.w3.bottomShadowColor); + } + } + if ((button.w3.shadowThickness > 0) && (button.pressed)) { + Dimension pressedAdjustment; + + pressedAdjustment = button.w3.shadowThickness / 2; + if (pressedAdjustment < 1) { + pressedAdjustment = 1; + } + x = button.label.w.x; + y = button.label.w.y; + button.label.w.x += pressedAdjustment; + button.label.w.y += pressedAdjustment; + paintLabel(app, draw, button.label); + button.label.w.x = x; + button.label.w.y = y; + } else { + paintLabel(app, draw, button.label); + } + if ((button.w3.shadowThickness <= 0) && (button.pressed)) { + Pixel tmp = button.w3.w.background; + button.w3.w.background = button.w3.w.foreground; + button.w3.w.foreground = tmp; + tmp = button.label.w.background; + button.label.w.background = button.label.w.foreground; + button.label.w.foreground = tmp; + } +} + +void paintIndicator(AppInfo *app, Drawable draw, IndicatorElement indicator) +{ + Position x; + Position y; + Dimension width; + Dimension height; + GC gc = app->dimGC; + + if (indicator.parent->w3.borderWidth > 0) { + XSetForeground(app->dpy, app->borderGC, + indicator.parent->w3.borderColor); + XFillRectangle(app->dpy, draw, app->borderGC, indicator.w.x, + indicator.w.y, indicator.w.width, indicator.w.height); + } + if (indicator.isLit) { + gc = app->brightGC; + } + x = (indicator.w.x + indicator.parent->w3.borderWidth); + y = (indicator.w.y + indicator.parent->w3.borderWidth); + width = (indicator.w.width - (2 * indicator.parent->w3.borderWidth)); + height = (indicator.w.height - (2 * indicator.parent->w3.borderWidth)); + XFillRectangle(app->dpy, draw, gc, x, y, width, height); + if (indicator.parent->w3.shadowThickness > 0) { + draw_shaded_rectangle(app->dpy, draw, x, y, width, height, + indicator.parent->w3.shadowThickness, + indicator.parent->w3.bottomShadowColor, + indicator.parent->w3.topShadowColor); + } +} + +void updateIndicatorElement(AppInfo *app, int i) +{ + DialogInfo *d = app->dialog; + + d->indicators[i].isLit = !(d->indicators[i].isLit); + paintIndicator(app, d->dialogWindow, d->indicators[i]); +} + +void updateIndicators(AppInfo *app, int condition) +{ + DialogInfo *d = app->dialog; + + if (condition > 0) { + /* Move forward one. */ + updateIndicatorElement(app, d->indicator.current); + if (d->indicator.current < (d->indicator.count - 1)) { + (d->indicator.current)++; + } else { + d->indicator.current = 0; + } + } else if (condition < 0) { + /* Move backward one. */ + if (d->indicator.current > 0) { + (d->indicator.current)--; + } else { + d->indicator.current = d->indicator.count - 1; + } + updateIndicatorElement(app, d->indicator.current); + } else { + /* Erase them all. */ + int i; + + for (i = 0; i < d->indicator.count; i++) { + d->indicators[i].isLit = False; + paintIndicator(app, d->dialogWindow, d->indicators[i]); + } + d->indicator.current = 0; + } + XSync(app->dpy, False); +} + +void paintDialog(AppInfo *app) +{ + DialogInfo *d = app->dialog; + Drawable draw = d->dialogWindow; + int i; + + XSetForeground(app->dpy, app->fillGC, d->w3.w.background); + XFillRectangle(app->dpy, draw, app->fillGC, 0, 0, + d->w3.w.width, d->w3.w.height); + if (d->w3.shadowThickness > 0) { + draw_shaded_rectangle(app->dpy, draw, 0, 0, + d->w3.w.width, d->w3.w.height, + d->w3.shadowThickness, + d->w3.topShadowColor, + d->w3.bottomShadowColor); + } + paintLabel(app, draw, d->label); + for (i = 0; i < d->indicator.count; i++) { + paintIndicator(app, draw, d->indicators[i]); + } + paintButton(app, draw, d->okButton); + paintButton(app, draw, d->cancelButton); + XSync(app->dpy, False); +} + +void performGrab(AppInfo *app, int grabType, char *grabTypeName, + Bool shouldGrab, Bool *isGrabbed) { + if ((!(shouldGrab)) || (*isGrabbed)) { + return; + } else if ((GRAB_KEYBOARD != grabType) && (GRAB_POINTER != grabType)) { + fprintf(stderr, "%s[%ld]: performGrab: invalid grab type (%d).\n", + app->appName, (long) app->pid, grabType); + return; + } else { + int status = GrabInvalidTime; /* keep gcc -Wall from complaining */ + unsigned int seconds = 0; + int helpful_message = 0; + /* keyboard and pointer */ + Window grabWindow = app->dialog->dialogWindow; + Bool ownerEvents = False; + Bool pointerMode = GrabModeAsync; + Bool keyboardMode = GrabModeAsync; + /* pointer only */ + unsigned int eventMask = ButtonPressMask | ButtonReleaseMask; + Window confineTo = None; + Cursor cursor = None; + + *isGrabbed = True; + + if (NULL == grabTypeName) { + fprintf(stderr, "%s[%ld]: performGrab: null grab type name.\n", + app->appName, (long) app->pid); + } + + if (0 == app->grabFailTimeout) { + /* Ensure we try to perform the grab at least once. */ + app->grabFailTimeout = 1; + } + while (seconds < app->grabFailTimeout) { + XSync(app->dpy, False); + switch (grabType) { + case GRAB_KEYBOARD: + status = XGrabKeyboard(app->dpy, grabWindow, ownerEvents, + pointerMode, keyboardMode, CurrentTime); + break; + case GRAB_POINTER: + status = XGrabPointer(app->dpy, grabWindow, ownerEvents, + eventMask, pointerMode, keyboardMode, + confineTo, cursor, CurrentTime); + break; + } + XSync(app->dpy, False); + if (GrabSuccess == status) { + if (helpful_message) { + fprintf(stderr, "%s[%ld]: Got %s.\n", + app->appName, (long) app->pid, grabTypeName); + } + break; + } + if (!helpful_message) { + fprintf(stderr, "%s[%ld]: Trying to grab %s ...\n", + app->appName, (long) app->pid, grabTypeName); + helpful_message = 1; + } + seconds += app->grabRetryInterval; + sleep(app->grabRetryInterval); + } + if (GrabSuccess != status) { + char *reason = "reason unknown"; + + switch (status) { + case AlreadyGrabbed: + reason = "someone else already has it"; + break; + case GrabFrozen: + reason = "someone else has frozen it"; + break; + case GrabInvalidTime: + reason = "bad grab time [this shouldn't happen]"; + break; + case GrabNotViewable: + reason = "grab not viewable [this shouldn't happen]"; + break; + } + fprintf(stderr, "%s[%ld]: Could not grab %s (%s)\n", + app->appName, (long) app->pid, grabTypeName, reason); + exitApp(app, EXIT_STATUS_ERROR); + } + } +} + + +void grabKeyboard(AppInfo *app) +{ + performGrab(app, GRAB_KEYBOARD, "keyboard", app->grabKeyboard, + &(app->isKeyboardGrabbed)); +} + +void ungrabKeyboard(AppInfo *app) +{ + if (app->grabKeyboard) { + XUngrabKeyboard(app->dpy, CurrentTime); + } +} + +void grabPointer(AppInfo *app) +{ + performGrab(app, GRAB_POINTER, "pointer", app->grabPointer, + &(app->isPointerGrabbed)); +} + +void ungrabPointer(AppInfo *app) +{ + if (app->grabPointer) { + XUngrabPointer(app->dpy, CurrentTime); + } +} + +void grabServer(AppInfo *app) +{ + if ((!(app->grabServer)) || (app->isServerGrabbed)) { + return; + } else { + app->isServerGrabbed = True; + XSync(app->dpy, False); + XGrabServer(app->dpy); + XSync(app->dpy, False); + } +} + +void ungrabServer(AppInfo *app) +{ + if (app->grabServer) { + XUngrabServer(app->dpy); + } +} + +void cleanUp(AppInfo *app) +{ + cancelInputTimeout(app); + XDestroyWindow(app->dpy, app->dialog->dialogWindow); + destroyGCs(app); + destroyDialog(app); + if (app->buf) { + memset(app->buf, 0, app->bufSize); + } + freeIf(app->buf); + ungrabPointer(app); + ungrabKeyboard(app); + ungrabServer(app); +} + +void exitApp(AppInfo *app, int exitCode) +{ + cleanUp(app); + exit(exitCode); +} + +void acceptAction(AppInfo *app) +{ + int status = append_to_buf(&(app->buf), &(app->bufSize), + &(app->bufIndex), '\0'); + if (APPEND_FAILURE == status) { + cleanUp(app); + outOfMemory(app, __LINE__); + } + fputs(app->buf, stdout); + fputc('\n', stdout); + exitApp(app, EXIT_STATUS_ACCEPT); +} + +void cancelAction(AppInfo *app) +{ + exitApp(app, EXIT_STATUS_CANCEL); +} + +void backspacePassphrase(AppInfo *app) +{ + if (0 >= app->bufIndex) { + XBell(app->dpy, 0); + return; + } + (app->bufIndex)--; + updateIndicators(app, -1); +} + +void erasePassphrase(AppInfo *app) +{ + if (0 >= app->bufIndex) { + XBell(app->dpy, 0); + return; + } + updateIndicators(app, 0); + app->bufIndex = 0; +} + +void addToPassphrase(AppInfo *app, char c) +{ + int status = append_to_buf(&(app->buf), &(app->bufSize), + &(app->bufIndex), c); + if (APPEND_FAILURE == status) { + cleanUp(app); + outOfMemory(app, __LINE__); + } + updateIndicators(app, 1); +} + +void handleKeyPress(AppInfo *app, XEvent *event) +{ + char s[2]; + int n; + + if (event->xkey.send_event) { + /* Pay no attention to synthetic key events. */ + return; + } + cancelInputTimeout(app); + n = XLookupString(&(event->xkey), s, 1, NULL, NULL); + + if (1 != n) { + return; + } + s[1] = '\0'; + switch (s[0]) { + case '\010': + case '\177': + backspacePassphrase(app); + break; + case '\025': + case '\030': + erasePassphrase(app); + break; + case '\012': + case '\015': + acceptAction(app); + break; + case '\033': + cancelAction(app); + break; + default: + addToPassphrase(app, s[0]); + break; + } +} + +Bool eventIsInsideButton(AppInfo *app, XEvent *event, ButtonInfo button) +{ + /* 'gcc -Wall' complains about 'app' being an unused parameter. + * Tough. We might want to use it later, and then we don't have + * to change it in each place it's called. Performance won't suffer. + */ + int status = False; + int x, y; + + switch(event->type) { + case ButtonPress: + case ButtonRelease: + x = event->xbutton.x; + y = event->xbutton.y; + break; + case MotionNotify: + x = event->xmotion.x; + y = event->xmotion.y; + break; + default: + return(False); + } + if ((x >= (button.w3.w.x + button.w3.borderWidth)) && + (x < (button.w3.w.x + button.w3.w.width - + (2 * button.w3.borderWidth))) && + (y >= (button.w3.w.y + button.w3.borderWidth)) && + (y < (button.w3.w.y + button.w3.w.height - + (2 * button.w3.borderWidth)))) { + status = True; + } + return(status); +} + +void handleButtonPress(AppInfo *app, XEvent *event) +{ + DialogInfo *d = app->dialog; + + cancelInputTimeout(app); + if (event->xbutton.button != Button1) { + return; + } + if (ButtonPress == event->type) { + if (eventIsInsideButton(app, event, d->okButton)) { + d->pressedButton = OK_BUTTON; + d->okButton.pressed = True; + paintButton(app, d->dialogWindow, d->okButton); + } else if (eventIsInsideButton(app, event, d->cancelButton)) { + d->pressedButton = CANCEL_BUTTON; + d->cancelButton.pressed = True; + paintButton(app, d->dialogWindow, d->cancelButton); + } else { + d->pressedButton = NO_BUTTON; + } + } else if (ButtonRelease == event->type) { + if (OK_BUTTON == d->pressedButton) { + if (eventIsInsideButton(app, event, d->okButton)) { + acceptAction(app); + } else { + if (d->okButton.pressed) { + d->okButton.pressed = False; + paintButton(app, d->dialogWindow, d->okButton); + } + } + } else if (CANCEL_BUTTON == d->pressedButton) { + if (eventIsInsideButton(app, event, d->cancelButton)) { + cancelAction(app); + } else { + if (d->cancelButton.pressed) { + d->cancelButton.pressed = False; + paintButton(app, d->dialogWindow, d->cancelButton); + } + } + } + d->pressedButton = NO_BUTTON; + } +} + +void handlePointerMotion(AppInfo *app, XEvent *event) +{ + DialogInfo *d = app->dialog; + + if (NO_BUTTON == d->pressedButton) { + return; + } else if (OK_BUTTON == d->pressedButton) { + if (eventIsInsideButton(app, event, d->okButton)) { + if (!(d->okButton.pressed)) { + d->okButton.pressed = True; + paintButton(app, d->dialogWindow, d->okButton); + } + } else { + if (d->okButton.pressed) { + d->okButton.pressed = False; + paintButton(app, d->dialogWindow, d->okButton); + } + } + } else if (CANCEL_BUTTON == d->pressedButton) { + if (eventIsInsideButton(app, event, d->cancelButton)) { + if (!(d->cancelButton.pressed)) { + d->cancelButton.pressed = True; + paintButton(app, d->dialogWindow, d->cancelButton); + } + } else { + if (d->cancelButton.pressed) { + d->cancelButton.pressed = False; + paintButton(app, d->dialogWindow, d->cancelButton); + } + } + } +} + +void handleInputTimeout(XtPointer data, XtIntervalId *timerId) +{ + /* 'gcc -Wall' complains about 'timerId' being an unused parameter. + * Tough. Xt forces us to have it here. Like it. + */ + AppInfo *app = (AppInfo *) data; + if (app->inputTimeoutActive) { + app->inputTimeoutActive = False; + fprintf(stderr, "%s[%ld]: *Yawn*...timed out after %lu seconds.\n", + app->appName, (long) app->pid, (app->inputTimeout / 1000)); + exitApp(app, EXIT_STATUS_TIMEOUT); + } +} + +void cancelInputTimeout(AppInfo *app) +{ + if (app->inputTimeoutActive) { + app->inputTimeoutActive = False; + XtRemoveTimeOut(app->inputTimeoutTimerId); + } +} + +int main(int argc, char **argv) +{ + AppInfo app; + XEvent event; + + memset(&app, 0, sizeof(app)); + + progclass = "SshAskpass"; + app.toplevelShell = XtAppInitialize(&(app.appContext), progclass, + NULL, 0, &argc, argv, + defaults, NULL, 0); + app.argc = argc; + app.argv = argv; + app.dpy = XtDisplay(app.toplevelShell); + app.screen = DefaultScreenOfDisplay(app.dpy); + app.rootWindow = RootWindowOfScreen(app.screen); + app.black = BlackPixel(app.dpy, DefaultScreen(app.dpy)); + app.white = WhitePixel(app.dpy, DefaultScreen(app.dpy)); + app.colormap = DefaultColormapOfScreen(app.screen); + app.resourceDb = XtDatabase(app.dpy); + XtGetApplicationNameAndClass(app.dpy, &progname, &progclass); + app.appName = progname; + app.appClass = progclass; + /* For resources.c. */ + db = app.resourceDb; + + /* Seconds after which keyboard/pointer grab fail. */ + app.grabFailTimeout = 5; + /* Number of seconds to wait between grab attempts. */ + app.grabRetryInterval = 1; + + app.pid = getpid(); + + { + struct rlimit resourceLimit; + int status; + + status = getrlimit(RLIMIT_CORE, &resourceLimit); + if (-1 == status) { + fprintf(stderr, "%s[%ld]: getrlimit failed (%s)\n", app.appName, + (long) app.pid, strerror(errno)); + exit(EXIT_STATUS_ERROR); + } + resourceLimit.rlim_cur = 0; + status = setrlimit(RLIMIT_CORE, &resourceLimit); + if (-1 == status) { + fprintf(stderr, "%s[%ld]: setrlimit failed (%s)\n", app.appName, + (long) app.pid, strerror(errno)); + exit(EXIT_STATUS_ERROR); + } + } + + app.xResolution = + WidthOfScreen(app.screen) * 1000 / WidthMMOfScreen(app.screen); + app.yResolution = + HeightOfScreen(app.screen) * 1000 / HeightMMOfScreen(app.screen); + + createDialog(&app); + createGCs(&app); + + app.eventMask = 0; + app.eventMask |= ExposureMask; + app.eventMask |= ButtonPressMask; + app.eventMask |= ButtonReleaseMask; + app.eventMask |= Button1MotionMask; + app.eventMask |= KeyPressMask; + + createDialogWindow(&app); + + XMapWindow(app.dpy, app.dialog->dialogWindow); + if (app.inputTimeout > 0) { + app.inputTimeoutActive = True; + app.inputTimeoutTimerId = + XtAppAddTimeOut(app.appContext, app.inputTimeout, + handleInputTimeout, (XtPointer) &app); + } + + + while(True) { + XtAppNextEvent(app.appContext, &event); + switch (event.type) { + case Expose: + grabServer(&app); + grabKeyboard(&app); + grabPointer(&app); + if (event.xexpose.count) { + break; + } + paintDialog(&app); + break; + case ButtonPress: + case ButtonRelease: + handleButtonPress(&app, &event); + break; + case MotionNotify: + handlePointerMotion(&app, &event); + case KeyPress: + handleKeyPress(&app, &event); + break; + case ClientMessage: + if ((32 == event.xclient.format) && + ((unsigned long) event.xclient.data.l[0] == + app.wmDeleteWindowAtom)) { + cancelAction(&app); + } + break; + default: + break; + } + } + + fprintf(stderr, "%s[%ld]: This should not happen.\n", app.appName, + (long) app.pid); + return(EXIT_STATUS_ANOMALY); +} + |