18db30ca8Sthorpej/* x11-ssh-askpass.c: A generic X11-based password dialog for OpenSSH. 2c056561aSmbalmer * created 1999-Nov-17 03:40 Jim Knoble <jmknoble@jmknoble.cx> 3c056561aSmbalmer * autodate: 2001-Feb-14 04:00 48db30ca8Sthorpej * 5c056561aSmbalmer * by Jim Knoble <jmknoble@jmknoble.cx> 6c056561aSmbalmer * Copyright (C) 1999,2000,2001 Jim Knoble 78db30ca8Sthorpej * 88db30ca8Sthorpej * Disclaimer: 98db30ca8Sthorpej * 108db30ca8Sthorpej * The software is provided "as is", without warranty of any kind, 118db30ca8Sthorpej * express or implied, including but not limited to the warranties of 128db30ca8Sthorpej * merchantability, fitness for a particular purpose and 138db30ca8Sthorpej * noninfringement. In no event shall the author(s) be liable for any 148db30ca8Sthorpej * claim, damages or other liability, whether in an action of 158db30ca8Sthorpej * contract, tort or otherwise, arising from, out of or in connection 168db30ca8Sthorpej * with the software or the use or other dealings in the software. 178db30ca8Sthorpej * 188db30ca8Sthorpej * Portions of this code are distantly derived from code in xscreensaver 198db30ca8Sthorpej * by Jamie Zawinski <jwz@jwz.org>. That code says: 208db30ca8Sthorpej * 218db30ca8Sthorpej * --------8<------------------------------------------------8<-------- 228db30ca8Sthorpej * xscreensaver, Copyright (c) 1991-1999 Jamie Zawinski <jwz@jwz.org> 238db30ca8Sthorpej * 248db30ca8Sthorpej * Permission to use, copy, modify, distribute, and sell this software and its 258db30ca8Sthorpej * documentation for any purpose is hereby granted without fee, provided that 268db30ca8Sthorpej * the above copyright notice appear in all copies and that both that 278db30ca8Sthorpej * copyright notice and this permission notice appear in supporting 288db30ca8Sthorpej * documentation. No representations are made about the suitability of this 298db30ca8Sthorpej * software for any purpose. It is provided "as is" without express or 308db30ca8Sthorpej * implied warranty. 318db30ca8Sthorpej * --------8<------------------------------------------------8<-------- 328db30ca8Sthorpej * 338db30ca8Sthorpej * The remainder of this code falls under the same permissions and 348db30ca8Sthorpej * provisions as those of the xscreensaver code. 358db30ca8Sthorpej */ 368db30ca8Sthorpej 37c056561aSmbalmer#include <ctype.h> 388db30ca8Sthorpej#include <stdio.h> 398db30ca8Sthorpej#include <stdlib.h> 408db30ca8Sthorpej#include <string.h> 418db30ca8Sthorpej 428db30ca8Sthorpej/* For (get|set)rlimit() ... */ 438db30ca8Sthorpej#include <sys/time.h> 448db30ca8Sthorpej#include <sys/resource.h> 45c056561aSmbalmer/* ... end */ 46c056561aSmbalmer/* For (get|set)rlimit(), sleep(), and getpid() ... */ 478db30ca8Sthorpej#include <unistd.h> 488db30ca8Sthorpej/* ... end */ 498db30ca8Sthorpej 508db30ca8Sthorpej/* For errno ... */ 518db30ca8Sthorpej#include <errno.h> 528db30ca8Sthorpej/* ... end */ 538db30ca8Sthorpej 548db30ca8Sthorpej#include <X11/Xlib.h> 558db30ca8Sthorpej#include <X11/Intrinsic.h> 568db30ca8Sthorpej#include <X11/Shell.h> 578db30ca8Sthorpej#include <X11/Xos.h> 58c056561aSmbalmer#include <X11/extensions/Xinerama.h> 598db30ca8Sthorpej#include "dynlist.h" 608db30ca8Sthorpej#include "drawing.h" 618db30ca8Sthorpej#include "resources.h" 628db30ca8Sthorpej#include "x11-ssh-askpass.h" 638db30ca8Sthorpej 648db30ca8Sthorpej#undef MAX 658db30ca8Sthorpej#define MAX(a,b) (((a) > (b)) ? (a) : (b)) 668db30ca8Sthorpej 678db30ca8Sthorpejchar *progname = NULL; 688db30ca8Sthorpejchar *progclass = NULL; 698db30ca8SthorpejXrmDatabase db = 0; 708db30ca8Sthorpej 718db30ca8Sthorpejstatic char *defaults[] = { 728db30ca8Sthorpej#include "SshAskpass_ad.h" 738db30ca8Sthorpej 0 748db30ca8Sthorpej}; 758db30ca8Sthorpej 768db30ca8Sthorpejvoid outOfMemory(AppInfo *app, int line) 778db30ca8Sthorpej{ 78c056561aSmbalmer fprintf(stderr, "%s[%ld]: Aaahhh! I ran out of memory at line %d.\n", 79c056561aSmbalmer app->appName, (long) app->pid, line); 808db30ca8Sthorpej exit(EXIT_STATUS_NO_MEMORY); 818db30ca8Sthorpej} 828db30ca8Sthorpej 838db30ca8Sthorpejvoid freeIf(void *p) 848db30ca8Sthorpej{ 858db30ca8Sthorpej if (p) { 868db30ca8Sthorpej free(p); 878db30ca8Sthorpej } 888db30ca8Sthorpej} 898db30ca8Sthorpej 908db30ca8Sthorpejvoid freeFontIf(AppInfo *app, XFontStruct *f) 918db30ca8Sthorpej{ 928db30ca8Sthorpej if (f) { 938db30ca8Sthorpej XFreeFont(app->dpy, f); 948db30ca8Sthorpej } 958db30ca8Sthorpej} 968db30ca8Sthorpej 978db30ca8SthorpejXFontStruct *getFontResource(AppInfo *app, char *instanceName, char *className) 988db30ca8Sthorpej{ 998db30ca8Sthorpej char *fallbackFont = "fixed"; 1008db30ca8Sthorpej 1018db30ca8Sthorpej XFontStruct *f = NULL; 1028db30ca8Sthorpej char *s = get_string_resource(instanceName, className); 1038db30ca8Sthorpej f = XLoadQueryFont(app->dpy, (s ? s : fallbackFont)); 1048db30ca8Sthorpej if (!f) { 1058db30ca8Sthorpej f = XLoadQueryFont(app->dpy, fallbackFont); 1068db30ca8Sthorpej } 1078db30ca8Sthorpej if (s) { 1088db30ca8Sthorpej free(s); 1098db30ca8Sthorpej } 1108db30ca8Sthorpej return(f); 1118db30ca8Sthorpej} 1128db30ca8Sthorpej 1138db30ca8Sthorpejchar *getStringResourceWithDefault(char *instanceName, char *className, 1148db30ca8Sthorpej char *defaultText) 1158db30ca8Sthorpej{ 1168db30ca8Sthorpej char *s = get_string_resource(instanceName, className); 1178db30ca8Sthorpej if (!s) { 1188db30ca8Sthorpej if (!defaultText) { 1198db30ca8Sthorpej s = strdup(""); 1208db30ca8Sthorpej } else { 1218db30ca8Sthorpej s = strdup(defaultText); 1228db30ca8Sthorpej } 1238db30ca8Sthorpej } 1248db30ca8Sthorpej return(s); 1258db30ca8Sthorpej} 1268db30ca8Sthorpej 127c056561aSmbalmerunsigned int getUnsignedIntegerResource(AppInfo *app, char *instanceName, 128c056561aSmbalmer char *className, 129c056561aSmbalmer unsigned int defaultValue) 130c056561aSmbalmer{ 131c056561aSmbalmer int n; 132c056561aSmbalmer unsigned int value; 133c056561aSmbalmer char c; 134c056561aSmbalmer char *s = get_string_resource(instanceName, className); 135c056561aSmbalmer char *cp = s; 136c056561aSmbalmer 137c056561aSmbalmer if (NULL == s) { 138c056561aSmbalmer return(defaultValue); 139c056561aSmbalmer } 140c056561aSmbalmer while ((*cp) && isspace(*cp)) { 141c056561aSmbalmer /* Skip whitespace. */ 142c056561aSmbalmer cp++; 143c056561aSmbalmer } 144c056561aSmbalmer if (*cp) { 145c056561aSmbalmer if (('0' == cp[0]) && cp[1]) { 146c056561aSmbalmer if (('x' == cp[1]) || ('X' == cp[1])) { 147c056561aSmbalmer /* Hex */ 148c056561aSmbalmer n = sscanf(cp + 2, "%x %c", &value, &c); 149c056561aSmbalmer } else { 150c056561aSmbalmer /* Octal */ 151c056561aSmbalmer n = sscanf(cp + 1, "%o %c", &value, &c); 152c056561aSmbalmer } 153c056561aSmbalmer if (1 == n) { 154c056561aSmbalmer free(s); 155c056561aSmbalmer return(value); 156c056561aSmbalmer } 157c056561aSmbalmer } else { 158c056561aSmbalmer /* Unsigned Decimal */ 159c056561aSmbalmer n = sscanf(cp, "%u %c", &value, &c); 160c056561aSmbalmer if (1 == n) { 161c056561aSmbalmer free(s); 162c056561aSmbalmer return(value); 163c056561aSmbalmer } 164c056561aSmbalmer } 165c056561aSmbalmer } 166c056561aSmbalmer /* If we get here, no conversion succeeded. */ 167c056561aSmbalmer fprintf(stderr, "%s[%ld]: invalid value '%s' for %s.\n", 168c056561aSmbalmer app->appName, (long) app->pid, s, instanceName); 169c056561aSmbalmer free(s); 170c056561aSmbalmer return(defaultValue); 171c056561aSmbalmer} 172c056561aSmbalmer 173c056561aSmbalmer/* Default resolution is 75 dots/inch. 1 in = 2.54 cm. */ 174c056561aSmbalmer#define DefaultResolution ((75 * 10000) / 254) 175c056561aSmbalmerlong getResolutionResource(AppInfo *app, char *instanceName, char *className, 176c056561aSmbalmer char *defaultResolutionSpec) 177c056561aSmbalmer{ 178c056561aSmbalmer char units[3]; 179c056561aSmbalmer char *s; 180c056561aSmbalmer int n; 181c056561aSmbalmer long resolution; 182c056561aSmbalmer unsigned int i; 183c056561aSmbalmer 184c056561aSmbalmer memset(units, 0, sizeof(units)); 185c056561aSmbalmer s = getStringResourceWithDefault(instanceName, className, 186c056561aSmbalmer defaultResolutionSpec); 187c056561aSmbalmer /* NOTE: The width of the %s format must be one less than 188c056561aSmbalmer * the length of the units[] array above! 189c056561aSmbalmer */ 190c056561aSmbalmer n = sscanf(s, "%ld / %2s", &resolution, units); 191c056561aSmbalmer if (n != 2) { 192c056561aSmbalmer fprintf(stderr, "%s[%ld]: invalid value '%s' for %s.\n", 193c056561aSmbalmer app->appName, (long) app->pid, s, instanceName); 194c056561aSmbalmer resolution = DefaultResolution; 195c056561aSmbalmer } else { 196c056561aSmbalmer if (resolution < 0) { 197c056561aSmbalmer /* Resolution specifications should not be negative. */ 198c056561aSmbalmer resolution = -(resolution); 199c056561aSmbalmer } 200c056561aSmbalmer for (i = 0; i < (sizeof(units) - 1); i++) { 201c056561aSmbalmer units[i] = tolower(units[i]); 202c056561aSmbalmer } 203c056561aSmbalmer if ((0 == strcmp(units, "in")) || 204c056561aSmbalmer (0 == strcmp(units, "i")) || 205c056561aSmbalmer (0 == strcmp(units, "\""))) { 206c056561aSmbalmer /* dots/inch */ 207c056561aSmbalmer resolution = resolution * 10000 / 254; 208c056561aSmbalmer } else if ((0 == strcmp(units, "m")) || 209c056561aSmbalmer (0 == strcmp(units, "me"))) { 210c056561aSmbalmer /* dots/meter; no conversion necessary */ 211c056561aSmbalmer ; 212c056561aSmbalmer } else { 213c056561aSmbalmer /* some unit we don't recognize; cringe and stare at the floor */ 214c056561aSmbalmer resolution = DefaultResolution; 215c056561aSmbalmer } 216c056561aSmbalmer } 217c056561aSmbalmer return(resolution); 218c056561aSmbalmer} 219c056561aSmbalmer#undef DefaultResolution 220c056561aSmbalmer 221c056561aSmbalmervoid calcTextObjectExtents(TextObject *t, XFontStruct *font) { 222c056561aSmbalmer if ((!t) || (!(t->text))) { 223c056561aSmbalmer return; 224c056561aSmbalmer } 225c056561aSmbalmer t->textLength = strlen(t->text); 226c056561aSmbalmer XTextExtents(font, t->text, t->textLength, &(t->direction), 227c056561aSmbalmer &(t->ascent), &(t->descent), &(t->overall)); 228c056561aSmbalmer} 229c056561aSmbalmer 2308db30ca8Sthorpejvoid calcLabelTextExtents(LabelInfo *label) 2318db30ca8Sthorpej{ 232c056561aSmbalmer TextObject *t; 233c056561aSmbalmer int first = 1; 234c056561aSmbalmer 235c056561aSmbalmer if ((!label) || (!(label->fullText)) || (!(label->font))) { 2368db30ca8Sthorpej return; 2378db30ca8Sthorpej } 238c056561aSmbalmer t = label->multiText; 239c056561aSmbalmer while (NULL != t) { 240c056561aSmbalmer if (first) { 241c056561aSmbalmer calcTextObjectExtents(t, label->font); 242c056561aSmbalmer first = 0; 243c056561aSmbalmer } else 244c056561aSmbalmer calcTextObjectExtents(t, label->fixedFont); 245c056561aSmbalmer label->w.height += (t->ascent + t->descent); 246c056561aSmbalmer if (label->w.width < t->overall.width) { 247c056561aSmbalmer label->w.width = t->overall.width; 248c056561aSmbalmer } 249c056561aSmbalmer t = t->next; 250c056561aSmbalmer } 2518db30ca8Sthorpej} 2528db30ca8Sthorpej 2538db30ca8Sthorpejvoid calcTotalButtonExtents(ButtonInfo *button) 2548db30ca8Sthorpej{ 2558db30ca8Sthorpej if (!button) { 2568db30ca8Sthorpej return; 2578db30ca8Sthorpej } 2588db30ca8Sthorpej button->w3.w.width = (button->w3.interiorWidth + 2598db30ca8Sthorpej (2 * button->w3.shadowThickness)); 2608db30ca8Sthorpej button->w3.w.width += (2 * button->w3.borderWidth); 2618db30ca8Sthorpej button->w3.w.height = (button->w3.interiorHeight + 2628db30ca8Sthorpej (2 * button->w3.shadowThickness)); 2638db30ca8Sthorpej button->w3.w.height += (2 * button->w3.borderWidth); 2648db30ca8Sthorpej} 2658db30ca8Sthorpej 2668db30ca8Sthorpejvoid calcButtonExtents(ButtonInfo *button) 2678db30ca8Sthorpej{ 2688db30ca8Sthorpej if (!button) { 2698db30ca8Sthorpej return; 2708db30ca8Sthorpej } 2718db30ca8Sthorpej calcLabelTextExtents(&(button->label)); 2728db30ca8Sthorpej button->w3.interiorWidth = (button->label.w.width + 2738db30ca8Sthorpej (2 * button->w3.horizontalSpacing)); 2748db30ca8Sthorpej button->w3.interiorHeight = (button->label.w.height + 2758db30ca8Sthorpej (2 * button->w3.verticalSpacing)); 2768db30ca8Sthorpej calcTotalButtonExtents(button); 2778db30ca8Sthorpej} 2788db30ca8Sthorpej 2798db30ca8Sthorpejvoid balanceButtonExtents(ButtonInfo *button1, ButtonInfo *button2) 2808db30ca8Sthorpej{ 2818db30ca8Sthorpej if ((!button1) || (!button2)) { 2828db30ca8Sthorpej return; 2838db30ca8Sthorpej } 2848db30ca8Sthorpej button1->w3.interiorWidth = button2->w3.interiorWidth = 2858db30ca8Sthorpej MAX(button1->w3.interiorWidth, button2->w3.interiorWidth); 2868db30ca8Sthorpej button1->w3.interiorHeight = button2->w3.interiorHeight = 2878db30ca8Sthorpej MAX(button1->w3.interiorHeight, button2->w3.interiorHeight); 2888db30ca8Sthorpej calcTotalButtonExtents(button1); 2898db30ca8Sthorpej calcTotalButtonExtents(button2); 2908db30ca8Sthorpej} 2918db30ca8Sthorpej 2928db30ca8Sthorpejvoid calcButtonLabelPosition(ButtonInfo *button) 2938db30ca8Sthorpej{ 2948db30ca8Sthorpej if (!button) { 2958db30ca8Sthorpej return; 2968db30ca8Sthorpej } 2978db30ca8Sthorpej button->label.w.x = button->w3.w.x + 2988db30ca8Sthorpej ((button->w3.w.width - button->label.w.width) / 2); 2998db30ca8Sthorpej button->label.w.y = button->w3.w.y + 300c056561aSmbalmer ((button->w3.w.height - button->label.w.height) / 2); 301c056561aSmbalmer} 302c056561aSmbalmer 303c056561aSmbalmerDimension scaleXDimension(AppInfo *app, Dimension unscaled) 304c056561aSmbalmer{ 305c056561aSmbalmer Dimension scaled; 306c056561aSmbalmer 307c056561aSmbalmer if (((app->defaultXResolution < app->xResolution) && 308c056561aSmbalmer ((app->defaultXResolution + app->xFuzz) < app->xResolution)) || 309c056561aSmbalmer ((app->xResolution < app->defaultXResolution) && 310c056561aSmbalmer ((app->xResolution + app->xFuzz) < app->defaultXResolution))) { 311c056561aSmbalmer scaled = (unscaled * app->xResolution) / app->defaultXResolution; 312c056561aSmbalmer } else { 313c056561aSmbalmer scaled = unscaled; 314c056561aSmbalmer } 315c056561aSmbalmer return(scaled); 316c056561aSmbalmer} 317c056561aSmbalmer 318c056561aSmbalmerDimension scaleYDimension(AppInfo *app, Dimension unscaled) 319c056561aSmbalmer{ 320c056561aSmbalmer Dimension scaled; 321c056561aSmbalmer 322c056561aSmbalmer if (((app->defaultYResolution < app->yResolution) && 323c056561aSmbalmer ((app->defaultYResolution + app->yFuzz) < app->yResolution)) || 324c056561aSmbalmer ((app->yResolution < app->defaultYResolution) && 325c056561aSmbalmer ((app->yResolution + app->yFuzz) < app->defaultYResolution))) { 326c056561aSmbalmer scaled = (unscaled * app->yResolution) / app->defaultYResolution; 327c056561aSmbalmer } else { 328c056561aSmbalmer scaled = unscaled; 329c056561aSmbalmer } 330c056561aSmbalmer return(scaled); 331c056561aSmbalmer} 332c056561aSmbalmer 333c056561aSmbalmer/* Assumes 's' is non-NULL. */ 334c056561aSmbalmerTextObject *createTextObject(AppInfo *app, char *s) 335c056561aSmbalmer{ 336c056561aSmbalmer TextObject *t = malloc(sizeof(*t)); 337c056561aSmbalmer if (NULL == t) { 338c056561aSmbalmer outOfMemory(app, __LINE__); 339c056561aSmbalmer } 340c056561aSmbalmer memset(t, 0, sizeof(*t)); 341c056561aSmbalmer if (('\n' == *s) || ('\0' == *s)) { 342c056561aSmbalmer t->text = " "; 343c056561aSmbalmer } else { 344c056561aSmbalmer t->text = s; 345c056561aSmbalmer } 346c056561aSmbalmer return(t); 347c056561aSmbalmer} 348c056561aSmbalmer 349c056561aSmbalmer/* Assumes 'label' object exists and is zeroed. */ 350c056561aSmbalmervoid createLabel(AppInfo *app, char *text, LabelInfo *label) 351c056561aSmbalmer{ 352c056561aSmbalmer char *substring; 353c056561aSmbalmer TextObject *t; 354c056561aSmbalmer 355c056561aSmbalmer if ((!app) || (!text)) { 356c056561aSmbalmer return; 357c056561aSmbalmer } 358c056561aSmbalmer label->fullText = strdup(text); 359c056561aSmbalmer label->multiText = createTextObject(app, label->fullText); 360c056561aSmbalmer t = label->multiText; 361c056561aSmbalmer substring = strchr(label->fullText, '\n'); 362c056561aSmbalmer while (NULL != substring) { 363c056561aSmbalmer *(substring++) = '\0'; 364c056561aSmbalmer t->next = createTextObject(app, substring); 365c056561aSmbalmer if (t->next) { 366c056561aSmbalmer t = t->next; 367c056561aSmbalmer } 368c056561aSmbalmer substring = strchr(substring, '\n'); 369c056561aSmbalmer } 3708db30ca8Sthorpej} 3718db30ca8Sthorpej 3728db30ca8Sthorpejvoid createDialog(AppInfo *app) 3738db30ca8Sthorpej{ 3748db30ca8Sthorpej DialogInfo *d; 375c056561aSmbalmer char *labelText; 3768db30ca8Sthorpej 3778db30ca8Sthorpej if (app->dialog) { 3788db30ca8Sthorpej return; 3798db30ca8Sthorpej } 3808db30ca8Sthorpej d = malloc(sizeof(*d)); 3818db30ca8Sthorpej if (NULL == d) { 3828db30ca8Sthorpej outOfMemory(app, __LINE__); 3838db30ca8Sthorpej } 3848db30ca8Sthorpej memset(d, 0, sizeof(*d)); 3858db30ca8Sthorpej 386c056561aSmbalmer app->grabKeyboard = 3878db30ca8Sthorpej get_boolean_resource("grabKeyboard", "GrabKeyboard", True); 3888db30ca8Sthorpej app->grabPointer = 3898db30ca8Sthorpej get_boolean_resource("grabPointer", "GrabPointer", False); 390c056561aSmbalmer app->grabServer = 3918db30ca8Sthorpej get_boolean_resource("grabServer", "GrabServer", False); 392c056561aSmbalmer 393c056561aSmbalmer /* inputTimeout resource specified in seconds for easy human interface. 394c056561aSmbalmer * Convert to milliseconds here. 395c056561aSmbalmer */ 396c056561aSmbalmer app->inputTimeout = (unsigned long) 1000 * 397c056561aSmbalmer getUnsignedIntegerResource(app, "inputTimeout", "InputTimeout", 0); 398c056561aSmbalmer 399c056561aSmbalmer app->defaultXResolution = 400c056561aSmbalmer getResolutionResource(app, "defaultXResolution", "DefaultXResolution", 401c056561aSmbalmer "75/in"); 402c056561aSmbalmer app->defaultYResolution = 403c056561aSmbalmer getResolutionResource(app, "defaultYResolution", "DefaultYResolution", 404c056561aSmbalmer "75/in"); 405c056561aSmbalmer app->xFuzz = 406c056561aSmbalmer getResolutionResource(app, "xResolutionFuzz", "XResolutionFuzz", "20/in"); 407c056561aSmbalmer app->yFuzz = 408c056561aSmbalmer getResolutionResource(app, "yResolutionFuzz", "YResolutionFuzz", "20/in"); 4098db30ca8Sthorpej 4108db30ca8Sthorpej d->title = 4118db30ca8Sthorpej getStringResourceWithDefault("dialog.title", "Dialog.Title", 4128db30ca8Sthorpej "OpenSSH Authentication Passphrase Request"); 4138db30ca8Sthorpej d->w3.w.foreground = 4148db30ca8Sthorpej get_pixel_resource("foreground", "Foreground", 4158db30ca8Sthorpej app->dpy, app->colormap, app->black); 4168db30ca8Sthorpej d->w3.w.background = 4178db30ca8Sthorpej get_pixel_resource("background", "Background", 4188db30ca8Sthorpej app->dpy, app->colormap, app->white); 4198db30ca8Sthorpej d->w3.topShadowColor = 4208db30ca8Sthorpej get_pixel_resource("topShadowColor", "TopShadowColor", 4218db30ca8Sthorpej app->dpy, app->colormap, app->white); 4228db30ca8Sthorpej d->w3.bottomShadowColor = 4238db30ca8Sthorpej get_pixel_resource("bottomShadowColor", "BottomShadowColor", 4248db30ca8Sthorpej app->dpy, app->colormap, app->black); 4258db30ca8Sthorpej d->w3.shadowThickness = 4268db30ca8Sthorpej get_integer_resource("shadowThickness", "ShadowThickness", 3); 4278db30ca8Sthorpej d->w3.borderColor = 4288db30ca8Sthorpej get_pixel_resource("borderColor", "BorderColor", 4298db30ca8Sthorpej app->dpy, app->colormap, app->black); 4308db30ca8Sthorpej d->w3.borderWidth = 4318db30ca8Sthorpej get_integer_resource("borderWidth", "BorderWidth", 1); 4328db30ca8Sthorpej 433c056561aSmbalmer d->w3.horizontalSpacing = scaleXDimension(app, 434c056561aSmbalmer get_integer_resource("horizontalSpacing", "Spacing", 5)); 435c056561aSmbalmer d->w3.verticalSpacing = scaleYDimension(app, 436c056561aSmbalmer get_integer_resource("verticalSpacing", "Spacing", 6)); 4378db30ca8Sthorpej 4388db30ca8Sthorpej if (2 == app->argc) { 439c056561aSmbalmer labelText = strdup(app->argv[1]); 4408db30ca8Sthorpej } else { 441c056561aSmbalmer labelText = 4428db30ca8Sthorpej getStringResourceWithDefault("dialog.label", "Dialog.Label", 4438db30ca8Sthorpej "Please enter your authentication passphrase:"); 4448db30ca8Sthorpej } 445c056561aSmbalmer createLabel(app, labelText, &(d->label)); 446c056561aSmbalmer freeIf(labelText); 4478db30ca8Sthorpej d->label.font = getFontResource(app, "dialog.font", "Dialog.Font"); 448c056561aSmbalmer d->label.fixedFont = getFontResource(app, "dialog.fixedFont", 449c056561aSmbalmer "Dialog.FixedFont"); 4508db30ca8Sthorpej calcLabelTextExtents(&(d->label)); 4518db30ca8Sthorpej d->label.w.foreground = d->w3.w.foreground; 4528db30ca8Sthorpej d->label.w.background = d->w3.w.background; 4538db30ca8Sthorpej 4548db30ca8Sthorpej d->okButton.w3.w.foreground = 4558db30ca8Sthorpej get_pixel_resource("okButton.foreground", "Button.Foreground", 4568db30ca8Sthorpej app->dpy, app->colormap, app->black); 4578db30ca8Sthorpej d->okButton.w3.w.background = 4588db30ca8Sthorpej get_pixel_resource("okButton.background", "Button.Background", 4598db30ca8Sthorpej app->dpy, app->colormap, app->white); 4608db30ca8Sthorpej d->okButton.w3.topShadowColor = 4618db30ca8Sthorpej get_pixel_resource("okButton.topShadowColor", "Button.TopShadowColor", 4628db30ca8Sthorpej app->dpy, app->colormap, app->white); 4638db30ca8Sthorpej d->okButton.w3.bottomShadowColor = 4648db30ca8Sthorpej get_pixel_resource("okButton.bottomShadowColor", 4658db30ca8Sthorpej "Button.BottomShadowColor", 4668db30ca8Sthorpej app->dpy, app->colormap, app->black); 4678db30ca8Sthorpej d->okButton.w3.shadowThickness = 4688db30ca8Sthorpej get_integer_resource("okButton.shadowThickness", 4698db30ca8Sthorpej "Button.ShadowThickness", 2); 4708db30ca8Sthorpej d->okButton.w3.borderColor = 4718db30ca8Sthorpej get_pixel_resource("okButton.borderColor", "Button.BorderColor", 4728db30ca8Sthorpej app->dpy, app->colormap, app->black); 4738db30ca8Sthorpej d->okButton.w3.borderWidth = 4748db30ca8Sthorpej get_integer_resource("okButton.borderWidth", "Button.BorderWidth", 1); 475c056561aSmbalmer d->okButton.w3.horizontalSpacing = scaleXDimension(app, 476c056561aSmbalmer get_integer_resource("okButton.horizontalSpacing", "Button.Spacing", 4)); 477c056561aSmbalmer d->okButton.w3.verticalSpacing = scaleYDimension(app, 478c056561aSmbalmer get_integer_resource("okButton.verticalSpacing", "Button.Spacing", 2)); 479c056561aSmbalmer labelText = 4808db30ca8Sthorpej getStringResourceWithDefault("okButton.label", "Button.Label", "OK"); 481c056561aSmbalmer createLabel(app, labelText, &(d->okButton.label)); 482c056561aSmbalmer freeIf(labelText); 4838db30ca8Sthorpej d->okButton.label.font = 4848db30ca8Sthorpej getFontResource(app, "okButton.font", "Button.Font"); 4858db30ca8Sthorpej calcButtonExtents(&(d->okButton)); 4868db30ca8Sthorpej d->okButton.label.w.foreground = d->okButton.w3.w.foreground; 4878db30ca8Sthorpej d->okButton.label.w.background = d->okButton.w3.w.background; 4888db30ca8Sthorpej 4898db30ca8Sthorpej d->cancelButton.w3.w.foreground = 4908db30ca8Sthorpej get_pixel_resource("cancelButton.foreground", "Button.Foreground", 4918db30ca8Sthorpej app->dpy, app->colormap, app->black); 4928db30ca8Sthorpej d->cancelButton.w3.w.background = 4938db30ca8Sthorpej get_pixel_resource("cancelButton.background", "Button.Background", 4948db30ca8Sthorpej app->dpy, app->colormap, app->white); 4958db30ca8Sthorpej d->cancelButton.w3.topShadowColor = 4968db30ca8Sthorpej get_pixel_resource("cancelButton.topShadowColor", 4978db30ca8Sthorpej "Button.TopShadowColor", 4988db30ca8Sthorpej app->dpy, app->colormap, app->white); 4998db30ca8Sthorpej d->cancelButton.w3.bottomShadowColor = 5008db30ca8Sthorpej get_pixel_resource("cancelButton.bottomShadowColor", 5018db30ca8Sthorpej "Button.BottomShadowColor", 5028db30ca8Sthorpej app->dpy, app->colormap, app->black); 5038db30ca8Sthorpej d->cancelButton.w3.shadowThickness = 5048db30ca8Sthorpej get_integer_resource("cancelButton.shadowThickness", 5058db30ca8Sthorpej "Button.ShadowThickness", 2); 5068db30ca8Sthorpej d->cancelButton.w3.borderColor = 5078db30ca8Sthorpej get_pixel_resource("cancelButton.borderColor", "Button.BorderColor", 5088db30ca8Sthorpej app->dpy, app->colormap, app->black); 5098db30ca8Sthorpej d->cancelButton.w3.borderWidth = 5108db30ca8Sthorpej get_integer_resource("cancelButton.borderWidth", "Button.BorderWidth", 5118db30ca8Sthorpej 1); 512c056561aSmbalmer d->cancelButton.w3.horizontalSpacing = scaleXDimension(app, 5138db30ca8Sthorpej get_integer_resource("cancelButton.horizontalSpacing", "Button.Spacing", 514c056561aSmbalmer 4)); 515c056561aSmbalmer d->cancelButton.w3.verticalSpacing = scaleYDimension(app, 5168db30ca8Sthorpej get_integer_resource("cancelButton.verticalSpacing", "Button.Spacing", 517c056561aSmbalmer 2)); 518c056561aSmbalmer labelText = 5198db30ca8Sthorpej getStringResourceWithDefault("cancelButton.label", "Button.Label", 5208db30ca8Sthorpej "Cancel"); 521c056561aSmbalmer createLabel(app, labelText, &(d->cancelButton.label)); 522c056561aSmbalmer freeIf(labelText); 5238db30ca8Sthorpej d->cancelButton.label.font = 5248db30ca8Sthorpej getFontResource(app, "cancelButton.font", "Button.Font"); 5258db30ca8Sthorpej calcButtonExtents(&(d->cancelButton)); 5268db30ca8Sthorpej d->cancelButton.label.w.foreground = d->cancelButton.w3.w.foreground; 5278db30ca8Sthorpej d->cancelButton.label.w.background = d->cancelButton.w3.w.background; 5288db30ca8Sthorpej 5298db30ca8Sthorpej balanceButtonExtents(&(d->okButton), &(d->cancelButton)); 5308db30ca8Sthorpej 5318db30ca8Sthorpej d->indicator.w3.w.foreground = 5328db30ca8Sthorpej get_pixel_resource("indicator.foreground", "Indicator.Foreground", 5338db30ca8Sthorpej app->dpy, app->colormap, app->black); 5348db30ca8Sthorpej d->indicator.w3.w.background = 5358db30ca8Sthorpej get_pixel_resource("indicator.background", "Indicator.Background", 5368db30ca8Sthorpej app->dpy, app->colormap, app->white); 537c056561aSmbalmer d->indicator.w3.w.width = scaleXDimension(app, 538c056561aSmbalmer get_integer_resource("indicator.width", "Indicator.Width", 15)); 539c056561aSmbalmer d->indicator.w3.w.height = scaleYDimension(app, 540c056561aSmbalmer get_integer_resource("indicator.height", "Indicator.Height", 7)); 5418db30ca8Sthorpej d->indicator.w3.topShadowColor = 5428db30ca8Sthorpej get_pixel_resource("indicator.topShadowColor", 5438db30ca8Sthorpej "Indicator.TopShadowColor", 5448db30ca8Sthorpej app->dpy, app->colormap, app->white); 5458db30ca8Sthorpej d->indicator.w3.bottomShadowColor = 5468db30ca8Sthorpej get_pixel_resource("indicator.bottomShadowColor", 5478db30ca8Sthorpej "Indicator.BottomShadowColor", 5488db30ca8Sthorpej app->dpy, app->colormap, app->black); 5498db30ca8Sthorpej d->indicator.w3.shadowThickness = 5508db30ca8Sthorpej get_integer_resource("indicator.shadowThickness", 5518db30ca8Sthorpej "Indicator.ShadowThickness", 2); 5528db30ca8Sthorpej d->indicator.w3.borderColor = 5538db30ca8Sthorpej get_pixel_resource("indicator.borderColor", "Indicator.BorderColor", 5548db30ca8Sthorpej app->dpy, app->colormap, app->black); 5558db30ca8Sthorpej d->indicator.w3.borderWidth = 5568db30ca8Sthorpej get_integer_resource("indicator.borderWidth", "Indicator.BorderWidth", 5578db30ca8Sthorpej 0); 558c056561aSmbalmer d->indicator.w3.horizontalSpacing = scaleXDimension(app, 5598db30ca8Sthorpej get_integer_resource("indicator.horizontalSpacing", "Indicator.Spacing", 560c056561aSmbalmer 2)); 561c056561aSmbalmer d->indicator.w3.verticalSpacing =scaleYDimension(app, 5628db30ca8Sthorpej get_integer_resource("indicator.verticalSpacing", "Indicator.Spacing", 563c056561aSmbalmer 4)); 5648db30ca8Sthorpej d->indicator.minimumCount = 5658db30ca8Sthorpej get_integer_resource("indicator.minimumCount", "Indicator.MinimumCount", 5668db30ca8Sthorpej 8); 5678db30ca8Sthorpej d->indicator.maximumCount = 5688db30ca8Sthorpej get_integer_resource("indicator.maximumCount", "Indicator.MaximumCount", 5698db30ca8Sthorpej 24); 5708db30ca8Sthorpej d->indicator.w3.interiorWidth = d->indicator.w3.w.width; 5718db30ca8Sthorpej d->indicator.w3.interiorHeight = d->indicator.w3.w.height; 5728db30ca8Sthorpej d->indicator.w3.w.width += (2 * d->indicator.w3.shadowThickness); 5738db30ca8Sthorpej d->indicator.w3.w.width += (2 * d->indicator.w3.borderWidth); 5748db30ca8Sthorpej d->indicator.w3.w.height += (2 * d->indicator.w3.shadowThickness); 5758db30ca8Sthorpej d->indicator.w3.w.height += (2 * d->indicator.w3.borderWidth); 5768db30ca8Sthorpej { 5778db30ca8Sthorpej /* Make sure the indicators can all fit on the screen. 5788db30ca8Sthorpej * 80% of the screen width seems fine. 5798db30ca8Sthorpej */ 580c056561aSmbalmer Dimension maxWidth = (app->screen_width * 8 / 10); 5818db30ca8Sthorpej Dimension extraSpace = ((2 * d->w3.horizontalSpacing) + 5828db30ca8Sthorpej (2 * d->w3.shadowThickness)); 5838db30ca8Sthorpej 5848db30ca8Sthorpej if (d->indicator.maximumCount < 8) { 5858db30ca8Sthorpej d->indicator.maximumCount = 8; 5868db30ca8Sthorpej } 5878db30ca8Sthorpej if (((d->indicator.maximumCount * d->indicator.w3.w.width) + 5888db30ca8Sthorpej ((d->indicator.maximumCount - 1) * 5898db30ca8Sthorpej d->indicator.w3.horizontalSpacing) + extraSpace) > maxWidth) { 5908db30ca8Sthorpej d->indicator.maximumCount = 5918db30ca8Sthorpej ((maxWidth - extraSpace - d->indicator.w3.w.width) / 5928db30ca8Sthorpej (d->indicator.w3.w.width + d->indicator.w3.horizontalSpacing)) 5938db30ca8Sthorpej + 1; 5948db30ca8Sthorpej } 5958db30ca8Sthorpej if (d->indicator.minimumCount <= 6) { 5968db30ca8Sthorpej d->indicator.minimumCount = 6; 5978db30ca8Sthorpej } 5988db30ca8Sthorpej if (d->indicator.minimumCount > d->indicator.maximumCount) { 5998db30ca8Sthorpej d->indicator.minimumCount = d->indicator.maximumCount; 6008db30ca8Sthorpej } 6018db30ca8Sthorpej } 6028db30ca8Sthorpej 6038db30ca8Sthorpej { 6048db30ca8Sthorpej /* Calculate the width and horizontal position of things. */ 6058db30ca8Sthorpej Dimension labelAreaWidth; 6068db30ca8Sthorpej Dimension buttonAreaWidth; 6078db30ca8Sthorpej Dimension indicatorAreaWidth; 6088db30ca8Sthorpej Dimension extraIndicatorSpace; 6098db30ca8Sthorpej Dimension singleIndicatorSpace; 6108db30ca8Sthorpej Dimension interButtonSpace; 6118db30ca8Sthorpej Dimension w; 6128db30ca8Sthorpej Position leftX; 6138db30ca8Sthorpej int i; 6148db30ca8Sthorpej 6158db30ca8Sthorpej labelAreaWidth = d->label.w.width + (2 * d->w3.horizontalSpacing); 6168db30ca8Sthorpej buttonAreaWidth = ((3 * d->w3.horizontalSpacing) + 6178db30ca8Sthorpej d->okButton.w3.w.width + 6188db30ca8Sthorpej d->cancelButton.w3.w.width); 6198db30ca8Sthorpej w = MAX(labelAreaWidth, buttonAreaWidth); 6208db30ca8Sthorpej extraIndicatorSpace = ((2 * d->w3.horizontalSpacing) + 6218db30ca8Sthorpej d->indicator.w3.w.width); 6228db30ca8Sthorpej singleIndicatorSpace = (d->indicator.w3.w.width + 6238db30ca8Sthorpej d->indicator.w3.horizontalSpacing); 6248db30ca8Sthorpej d->indicator.count = ((w - extraIndicatorSpace) / singleIndicatorSpace); 6258db30ca8Sthorpej d->indicator.current = 0; 6268db30ca8Sthorpej d->indicator.count++; /* For gatepost indicator in extra space. */ 6278db30ca8Sthorpej if (((w - extraIndicatorSpace) % singleIndicatorSpace) > 6288db30ca8Sthorpej (singleIndicatorSpace / 2)) { 6298db30ca8Sthorpej d->indicator.count++; 6308db30ca8Sthorpej } 6318db30ca8Sthorpej if (d->indicator.count < d->indicator.minimumCount) { 6328db30ca8Sthorpej d->indicator.count = d->indicator.minimumCount; 6338db30ca8Sthorpej } 6348db30ca8Sthorpej if (d->indicator.count > d->indicator.maximumCount) { 6358db30ca8Sthorpej d->indicator.count = d->indicator.maximumCount; 6368db30ca8Sthorpej } 6378db30ca8Sthorpej indicatorAreaWidth = ((singleIndicatorSpace * (d->indicator.count - 1)) + 6388db30ca8Sthorpej extraIndicatorSpace); 6398db30ca8Sthorpej d->w3.interiorWidth = MAX(w, indicatorAreaWidth); 6408db30ca8Sthorpej d->w3.w.width = d->w3.interiorWidth + (2 * d->w3.shadowThickness); 6418db30ca8Sthorpej 6428db30ca8Sthorpej leftX = (d->w3.w.width - d->label.w.width) / 2; 6438db30ca8Sthorpej d->label.w.x = leftX; 6448db30ca8Sthorpej 6458db30ca8Sthorpej leftX = ((d->w3.w.width - 6468db30ca8Sthorpej (d->indicator.count * d->indicator.w3.w.width) - 6478db30ca8Sthorpej ((d->indicator.count - 1) * d->indicator.w3.horizontalSpacing)) 6488db30ca8Sthorpej / 2); 6498db30ca8Sthorpej { 6508db30ca8Sthorpej int n = d->indicator.count * sizeof(IndicatorElement); 6518db30ca8Sthorpej d->indicators = malloc(n); 6528db30ca8Sthorpej if (NULL == d->indicators) { 6538db30ca8Sthorpej destroyDialog(app); 6548db30ca8Sthorpej outOfMemory(app, __LINE__); 6558db30ca8Sthorpej } 6568db30ca8Sthorpej memset(d->indicators, 0, n); 6578db30ca8Sthorpej } 6588db30ca8Sthorpej d->indicators[0].parent = &(d->indicator); 6598db30ca8Sthorpej d->indicators[0].w.x = d->indicator.w3.w.x = leftX; 6608db30ca8Sthorpej d->indicators[0].w.width = d->indicator.w3.w.width; 6618db30ca8Sthorpej d->indicators[0].isLit = False; 6628db30ca8Sthorpej for (i = 1; i < d->indicator.count; i++) { 6638db30ca8Sthorpej d->indicators[i].parent = &(d->indicator); 6648db30ca8Sthorpej d->indicators[i].w.x = (d->indicators[i - 1].w.x + 6658db30ca8Sthorpej d->indicator.w3.w.width + 6668db30ca8Sthorpej d->indicator.w3.horizontalSpacing); 6678db30ca8Sthorpej d->indicators[i].w.width = d->indicator.w3.w.width; 6688db30ca8Sthorpej d->indicators[i].isLit = False; 6698db30ca8Sthorpej } 6708db30ca8Sthorpej interButtonSpace = ((d->w3.interiorWidth - d->okButton.w3.w.width - 6718db30ca8Sthorpej d->cancelButton.w3.w.width) / 3); 6728db30ca8Sthorpej d->okButton.w3.w.x = interButtonSpace + d->w3.shadowThickness; 6738db30ca8Sthorpej d->cancelButton.w3.w.x = (d->okButton.w3.w.x + d->okButton.w3.w.width + 6748db30ca8Sthorpej interButtonSpace); 6758db30ca8Sthorpej } 6768db30ca8Sthorpej { 6778db30ca8Sthorpej /* Calculate the height and vertical position of things. */ 6788db30ca8Sthorpej int i; 6798db30ca8Sthorpej 6808db30ca8Sthorpej d->w3.interiorHeight = ((4 * d->w3.verticalSpacing) + 6818db30ca8Sthorpej (2 * d->indicator.w3.verticalSpacing) + 6828db30ca8Sthorpej d->label.w.height + 6838db30ca8Sthorpej d->indicator.w3.w.height + 6848db30ca8Sthorpej d->okButton.w3.w.height); 6858db30ca8Sthorpej d->w3.w.height = d->w3.interiorHeight + (2 * d->w3.shadowThickness); 686c056561aSmbalmer d->label.w.y = d->w3.shadowThickness + d->w3.verticalSpacing; 687c056561aSmbalmer d->indicator.w3.w.y = (d->label.w.y + d->label.w.height + 6888db30ca8Sthorpej d->w3.verticalSpacing + 6898db30ca8Sthorpej d->indicator.w3.verticalSpacing); 6908db30ca8Sthorpej for (i = 0; i < d->indicator.count; i++) { 6918db30ca8Sthorpej d->indicators[i].w.y = d->indicator.w3.w.y; 6928db30ca8Sthorpej d->indicators[i].w.height = d->indicator.w3.w.height; 6938db30ca8Sthorpej } 6948db30ca8Sthorpej d->okButton.w3.w.y = d->cancelButton.w3.w.y = 6958db30ca8Sthorpej (d->indicator.w3.w.y + d->indicator.w3.w.height + 6968db30ca8Sthorpej d->w3.verticalSpacing + d->indicator.w3.verticalSpacing); 6978db30ca8Sthorpej } 6988db30ca8Sthorpej calcButtonLabelPosition(&(d->okButton)); 6998db30ca8Sthorpej calcButtonLabelPosition(&(d->cancelButton)); 7008db30ca8Sthorpej 701c056561aSmbalmer d->w3.w.x = (app->screen_width - d->w3.w.width) / 2; 702c056561aSmbalmer d->w3.w.y = (app->screen_height - d->w3.w.height) / 3; 7038db30ca8Sthorpej 7048db30ca8Sthorpej app->dialog = d; 7058db30ca8Sthorpej} 7068db30ca8Sthorpej 707c056561aSmbalmervoid destroyLabel(AppInfo *app, LabelInfo *label) 708c056561aSmbalmer{ 709c056561aSmbalmer TextObject *thisTextObject; 710c056561aSmbalmer TextObject *nextTextObject; 711c056561aSmbalmer 712c056561aSmbalmer thisTextObject = label->multiText; 713c056561aSmbalmer nextTextObject = thisTextObject->next; 714c056561aSmbalmer freeIf(thisTextObject); 715c056561aSmbalmer while (NULL != nextTextObject) { 716c056561aSmbalmer thisTextObject = nextTextObject; 717c056561aSmbalmer nextTextObject = thisTextObject->next; 718c056561aSmbalmer freeIf(thisTextObject); 719c056561aSmbalmer } 720c056561aSmbalmer freeIf(label->fullText); 721c056561aSmbalmer freeFontIf(app, label->font); 722c056561aSmbalmer freeFontIf(app, label->fixedFont); 723c056561aSmbalmer} 724c056561aSmbalmer 7258db30ca8Sthorpejvoid destroyDialog(AppInfo *app) 7268db30ca8Sthorpej{ 7278db30ca8Sthorpej DialogInfo *d = app->dialog; 7288db30ca8Sthorpej 7298db30ca8Sthorpej freeIf(d->title); 7308db30ca8Sthorpej freeIf(d->indicators); 731c056561aSmbalmer 732c056561aSmbalmer destroyLabel(app, &(d->label)); 733c056561aSmbalmer destroyLabel(app, &(d->okButton.label)); 734c056561aSmbalmer destroyLabel(app, &(d->cancelButton.label)); 7358db30ca8Sthorpej 7368db30ca8Sthorpej XFree(d->sizeHints); 7378db30ca8Sthorpej XFree(d->wmHints); 7388db30ca8Sthorpej XFree(d->classHints); 7398db30ca8Sthorpej XFree(d->windowName.value); 7408db30ca8Sthorpej 7418db30ca8Sthorpej freeIf(d); 7428db30ca8Sthorpej} 7438db30ca8Sthorpej 7448db30ca8Sthorpejvoid createDialogWindow(AppInfo *app) 7458db30ca8Sthorpej{ 7468db30ca8Sthorpej XSetWindowAttributes attr; 7478db30ca8Sthorpej unsigned long attrMask = 0; 7488db30ca8Sthorpej DialogInfo *d = app->dialog; 7498db30ca8Sthorpej 7508db30ca8Sthorpej attr.background_pixel = d->w3.w.background; 7518db30ca8Sthorpej attrMask |= CWBackPixel; 7528db30ca8Sthorpej attr.border_pixel = d->w3.borderColor; 7538db30ca8Sthorpej attrMask |= CWBorderPixel; 7548db30ca8Sthorpej attr.cursor = None; 7558db30ca8Sthorpej attrMask |= CWCursor; 756c056561aSmbalmer attr.event_mask = app->eventMask; 7578db30ca8Sthorpej attrMask |= CWEventMask; 7588db30ca8Sthorpej 7598db30ca8Sthorpej d->dialogWindow = XCreateWindow(app->dpy, app->rootWindow, 7608db30ca8Sthorpej d->w3.w.x, d->w3.w.y, 7618db30ca8Sthorpej d->w3.w.width, d->w3.w.height, 7628db30ca8Sthorpej d->w3.borderWidth, 7638db30ca8Sthorpej DefaultDepthOfScreen(app->screen), 7648db30ca8Sthorpej InputOutput, 7658db30ca8Sthorpej DefaultVisualOfScreen(app->screen), 7668db30ca8Sthorpej attrMask, &attr); 7678db30ca8Sthorpej 7688db30ca8Sthorpej d->sizeHints = XAllocSizeHints(); 7698db30ca8Sthorpej if (!(d->sizeHints)) { 7708db30ca8Sthorpej destroyDialog(app); 7718db30ca8Sthorpej outOfMemory(app, __LINE__); 7728db30ca8Sthorpej } 7738db30ca8Sthorpej d->sizeHints->flags = 0; 7748db30ca8Sthorpej d->sizeHints->flags |= PPosition; 7758db30ca8Sthorpej d->sizeHints->flags |= PSize; 7768db30ca8Sthorpej d->sizeHints->min_width = d->w3.w.width; 7778db30ca8Sthorpej d->sizeHints->min_height = d->w3.w.height; 7788db30ca8Sthorpej d->sizeHints->flags |= PMinSize; 7798db30ca8Sthorpej d->sizeHints->max_width = d->w3.w.width; 7808db30ca8Sthorpej d->sizeHints->max_height = d->w3.w.height; 7818db30ca8Sthorpej d->sizeHints->flags |= PMaxSize; 7828db30ca8Sthorpej d->sizeHints->base_width = d->w3.w.width; 7838db30ca8Sthorpej d->sizeHints->base_height = d->w3.w.height; 7848db30ca8Sthorpej d->sizeHints->flags |= PBaseSize; 7858db30ca8Sthorpej 7868db30ca8Sthorpej d->wmHints = XAllocWMHints(); 7878db30ca8Sthorpej if (!(d->wmHints)) { 7888db30ca8Sthorpej destroyDialog(app); 7898db30ca8Sthorpej outOfMemory(app, __LINE__); 7908db30ca8Sthorpej } 7918db30ca8Sthorpej d->wmHints->flags = 0; 7928db30ca8Sthorpej d->wmHints->input = True; 7938db30ca8Sthorpej d->wmHints->flags |= InputHint; 7948db30ca8Sthorpej d->wmHints->initial_state = NormalState; 7958db30ca8Sthorpej d->wmHints->flags |= StateHint; 7968db30ca8Sthorpej 7978db30ca8Sthorpej d->classHints = XAllocClassHint(); 7988db30ca8Sthorpej if (!(d->classHints)) { 7998db30ca8Sthorpej destroyDialog(app); 8008db30ca8Sthorpej outOfMemory(app, __LINE__); 8018db30ca8Sthorpej } 8028db30ca8Sthorpej d->classHints->res_name = app->appName; 8038db30ca8Sthorpej d->classHints->res_class = app->appClass; 8048db30ca8Sthorpej 8058db30ca8Sthorpej if (!XStringListToTextProperty(&(d->title), 1, &(d->windowName))) { 8068db30ca8Sthorpej destroyDialog(app); 8078db30ca8Sthorpej outOfMemory(app, __LINE__); 8088db30ca8Sthorpej } 8098db30ca8Sthorpej XSetWMProperties(app->dpy, d->dialogWindow, &(d->windowName), NULL, 8108db30ca8Sthorpej app->argv, app->argc, d->sizeHints, 8118db30ca8Sthorpej d->wmHints, d->classHints); 8128db30ca8Sthorpej XSetTransientForHint(app->dpy, d->dialogWindow, d->dialogWindow); 8138db30ca8Sthorpej 8148db30ca8Sthorpej app->wmDeleteWindowAtom = XInternAtom(app->dpy, "WM_DELETE_WINDOW", False); 8158db30ca8Sthorpej XSetWMProtocols(app->dpy, d->dialogWindow, &(app->wmDeleteWindowAtom), 1); 8168db30ca8Sthorpej} 8178db30ca8Sthorpej 8188db30ca8Sthorpejvoid createGCs(AppInfo *app) 8198db30ca8Sthorpej{ 8208db30ca8Sthorpej DialogInfo *d = app->dialog; 8218db30ca8Sthorpej 8228db30ca8Sthorpej XGCValues gcv; 8238db30ca8Sthorpej unsigned long gcvMask; 8248db30ca8Sthorpej 8258db30ca8Sthorpej gcvMask = 0; 8268db30ca8Sthorpej gcv.foreground = d->w3.w.background; 8278db30ca8Sthorpej gcvMask |= GCForeground; 8288db30ca8Sthorpej gcv.fill_style = FillSolid; 8298db30ca8Sthorpej gcvMask |= GCFillStyle; 8308db30ca8Sthorpej app->fillGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); 8318db30ca8Sthorpej 8328db30ca8Sthorpej gcvMask = 0; 8338db30ca8Sthorpej gcv.foreground = d->w3.borderColor; 8348db30ca8Sthorpej gcvMask |= GCForeground; 8358db30ca8Sthorpej gcv.line_width = d->w3.borderWidth; 8368db30ca8Sthorpej gcvMask |= GCLineWidth; 8378db30ca8Sthorpej gcv.line_style = LineSolid; 8388db30ca8Sthorpej gcvMask |= GCLineStyle; 8398db30ca8Sthorpej gcv.cap_style = CapButt; 8408db30ca8Sthorpej gcvMask |= GCCapStyle; 8418db30ca8Sthorpej gcv.join_style = JoinMiter; 8428db30ca8Sthorpej gcvMask |= GCJoinStyle; 8438db30ca8Sthorpej app->borderGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); 8448db30ca8Sthorpej 8458db30ca8Sthorpej gcvMask = 0; 8468db30ca8Sthorpej gcv.foreground = d->label.w.foreground; 8478db30ca8Sthorpej gcvMask |= GCForeground; 8488db30ca8Sthorpej gcv.background = d->label.w.background; 8498db30ca8Sthorpej gcvMask |= GCBackground; 8508db30ca8Sthorpej gcv.font = d->label.font->fid; 8518db30ca8Sthorpej gcvMask |= GCFont; 8528db30ca8Sthorpej app->textGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); 8538db30ca8Sthorpej 8548db30ca8Sthorpej gcvMask = 0; 8558db30ca8Sthorpej gcv.foreground = d->indicator.w3.w.foreground; 8568db30ca8Sthorpej gcvMask |= GCForeground; 8578db30ca8Sthorpej gcv.fill_style = FillSolid; 8588db30ca8Sthorpej gcvMask |= GCFillStyle; 8598db30ca8Sthorpej app->brightGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); 8608db30ca8Sthorpej 8618db30ca8Sthorpej gcvMask = 0; 8628db30ca8Sthorpej gcv.foreground = d->indicator.w3.w.background; 8638db30ca8Sthorpej gcvMask |= GCForeground; 8648db30ca8Sthorpej gcv.fill_style = FillSolid; 8658db30ca8Sthorpej gcvMask |= GCFillStyle; 8668db30ca8Sthorpej app->dimGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); 8678db30ca8Sthorpej} 8688db30ca8Sthorpej 8698db30ca8Sthorpejvoid destroyGCs(AppInfo *app) 8708db30ca8Sthorpej{ 8718db30ca8Sthorpej XFreeGC(app->dpy, app->fillGC); 8728db30ca8Sthorpej XFreeGC(app->dpy, app->borderGC); 8738db30ca8Sthorpej XFreeGC(app->dpy, app->textGC); 8748db30ca8Sthorpej XFreeGC(app->dpy, app->brightGC); 8758db30ca8Sthorpej XFreeGC(app->dpy, app->dimGC); 8768db30ca8Sthorpej} 8778db30ca8Sthorpej 8788db30ca8Sthorpejvoid paintLabel(AppInfo *app, Drawable draw, LabelInfo label) 8798db30ca8Sthorpej{ 880c056561aSmbalmer TextObject *t; 881c056561aSmbalmer Position x; 882c056561aSmbalmer Position y; 883c056561aSmbalmer int first = 1; 884c056561aSmbalmer 885c056561aSmbalmer if (!(label.fullText)) { 8868db30ca8Sthorpej return; 8878db30ca8Sthorpej } 8888db30ca8Sthorpej XSetForeground(app->dpy, app->textGC, label.w.foreground); 8898db30ca8Sthorpej XSetBackground(app->dpy, app->textGC, label.w.background); 8908db30ca8Sthorpej XSetFont(app->dpy, app->textGC, label.font->fid); 891c056561aSmbalmer 892c056561aSmbalmer t = label.multiText; 893c056561aSmbalmer x = label.w.x; 894c056561aSmbalmer y = label.w.y + t->ascent; 895c056561aSmbalmer while (NULL != t) { 896c056561aSmbalmer if (!first) 897c056561aSmbalmer XSetFont(app->dpy, app->textGC, label.fixedFont->fid); 898c056561aSmbalmer else 899c056561aSmbalmer first = 0; 900c056561aSmbalmer 901c056561aSmbalmer if (t->text) { 902c056561aSmbalmer XDrawString(app->dpy, draw, app->textGC, x, y, t->text, 903c056561aSmbalmer t->textLength); 904c056561aSmbalmer } 905c056561aSmbalmer y += t->descent; 906c056561aSmbalmer t = t->next; 907c056561aSmbalmer if (t) { 908c056561aSmbalmer y += t->ascent; 909c056561aSmbalmer } 910c056561aSmbalmer } 9118db30ca8Sthorpej} 9128db30ca8Sthorpej 9138db30ca8Sthorpejvoid paintButton(AppInfo *app, Drawable draw, ButtonInfo button) 9148db30ca8Sthorpej{ 9158db30ca8Sthorpej Position x; 9168db30ca8Sthorpej Position y; 9178db30ca8Sthorpej Dimension width; 9188db30ca8Sthorpej Dimension height; 9198db30ca8Sthorpej 9208db30ca8Sthorpej if (button.w3.borderWidth > 0) { 9218db30ca8Sthorpej XSetForeground(app->dpy, app->borderGC, button.w3.borderColor); 9228db30ca8Sthorpej XFillRectangle(app->dpy, draw, app->borderGC, button.w3.w.x, 9238db30ca8Sthorpej button.w3.w.y, button.w3.w.width, button.w3.w.height); 9248db30ca8Sthorpej } 9258db30ca8Sthorpej if ((button.w3.shadowThickness <= 0) && (button.pressed)) { 9268db30ca8Sthorpej Pixel tmp = button.w3.w.background; 9278db30ca8Sthorpej button.w3.w.background = button.w3.w.foreground; 9288db30ca8Sthorpej button.w3.w.foreground = tmp; 9298db30ca8Sthorpej tmp = button.label.w.background; 9308db30ca8Sthorpej button.label.w.background = button.label.w.foreground; 9318db30ca8Sthorpej button.label.w.foreground = tmp; 9328db30ca8Sthorpej } 9338db30ca8Sthorpej x = (button.w3.w.x + button.w3.borderWidth); 9348db30ca8Sthorpej y = (button.w3.w.y + button.w3.borderWidth); 9358db30ca8Sthorpej width = (button.w3.w.width - (2 * button.w3.borderWidth)); 9368db30ca8Sthorpej height = (button.w3.w.height - (2 * button.w3.borderWidth)); 9378db30ca8Sthorpej if ((button.w3.shadowThickness > 0) && (button.pressed)) { 9388db30ca8Sthorpej XSetForeground(app->dpy, app->fillGC, button.w3.topShadowColor); 9398db30ca8Sthorpej } else { 9408db30ca8Sthorpej XSetForeground(app->dpy, app->fillGC, button.w3.w.background); 9418db30ca8Sthorpej } 9428db30ca8Sthorpej XFillRectangle(app->dpy, draw, app->fillGC, x, y, width, height); 9438db30ca8Sthorpej if (button.w3.shadowThickness > 0) { 9448db30ca8Sthorpej if (button.pressed) { 9458db30ca8Sthorpej draw_shaded_rectangle(app->dpy, draw, x, y, width, height, 9468db30ca8Sthorpej button.w3.shadowThickness, 9478db30ca8Sthorpej button.w3.bottomShadowColor, 9488db30ca8Sthorpej button.w3.topShadowColor); 9498db30ca8Sthorpej } else { 9508db30ca8Sthorpej draw_shaded_rectangle(app->dpy, draw, x, y, width, height, 9518db30ca8Sthorpej button.w3.shadowThickness, 9528db30ca8Sthorpej button.w3.topShadowColor, 9538db30ca8Sthorpej button.w3.bottomShadowColor); 9548db30ca8Sthorpej } 9558db30ca8Sthorpej } 956c056561aSmbalmer if ((button.w3.shadowThickness > 0) && (button.pressed)) { 957c056561aSmbalmer Dimension pressedAdjustment; 958c056561aSmbalmer 959c056561aSmbalmer pressedAdjustment = button.w3.shadowThickness / 2; 960c056561aSmbalmer if (pressedAdjustment < 1) { 961c056561aSmbalmer pressedAdjustment = 1; 962c056561aSmbalmer } 963c056561aSmbalmer x = button.label.w.x; 964c056561aSmbalmer y = button.label.w.y; 965c056561aSmbalmer button.label.w.x += pressedAdjustment; 966c056561aSmbalmer button.label.w.y += pressedAdjustment; 967c056561aSmbalmer paintLabel(app, draw, button.label); 968c056561aSmbalmer button.label.w.x = x; 969c056561aSmbalmer button.label.w.y = y; 970c056561aSmbalmer } else { 971c056561aSmbalmer paintLabel(app, draw, button.label); 972c056561aSmbalmer } 9738db30ca8Sthorpej if ((button.w3.shadowThickness <= 0) && (button.pressed)) { 9748db30ca8Sthorpej Pixel tmp = button.w3.w.background; 9758db30ca8Sthorpej button.w3.w.background = button.w3.w.foreground; 9768db30ca8Sthorpej button.w3.w.foreground = tmp; 9778db30ca8Sthorpej tmp = button.label.w.background; 9788db30ca8Sthorpej button.label.w.background = button.label.w.foreground; 9798db30ca8Sthorpej button.label.w.foreground = tmp; 9808db30ca8Sthorpej } 9818db30ca8Sthorpej} 9828db30ca8Sthorpej 9838db30ca8Sthorpejvoid paintIndicator(AppInfo *app, Drawable draw, IndicatorElement indicator) 9848db30ca8Sthorpej{ 9858db30ca8Sthorpej Position x; 9868db30ca8Sthorpej Position y; 9878db30ca8Sthorpej Dimension width; 9888db30ca8Sthorpej Dimension height; 9898db30ca8Sthorpej GC gc = app->dimGC; 9908db30ca8Sthorpej 9918db30ca8Sthorpej if (indicator.parent->w3.borderWidth > 0) { 9928db30ca8Sthorpej XSetForeground(app->dpy, app->borderGC, 9938db30ca8Sthorpej indicator.parent->w3.borderColor); 9948db30ca8Sthorpej XFillRectangle(app->dpy, draw, app->borderGC, indicator.w.x, 9958db30ca8Sthorpej indicator.w.y, indicator.w.width, indicator.w.height); 9968db30ca8Sthorpej } 9978db30ca8Sthorpej if (indicator.isLit) { 9988db30ca8Sthorpej gc = app->brightGC; 9998db30ca8Sthorpej } 10008db30ca8Sthorpej x = (indicator.w.x + indicator.parent->w3.borderWidth); 10018db30ca8Sthorpej y = (indicator.w.y + indicator.parent->w3.borderWidth); 10028db30ca8Sthorpej width = (indicator.w.width - (2 * indicator.parent->w3.borderWidth)); 10038db30ca8Sthorpej height = (indicator.w.height - (2 * indicator.parent->w3.borderWidth)); 10048db30ca8Sthorpej XFillRectangle(app->dpy, draw, gc, x, y, width, height); 10058db30ca8Sthorpej if (indicator.parent->w3.shadowThickness > 0) { 10068db30ca8Sthorpej draw_shaded_rectangle(app->dpy, draw, x, y, width, height, 10078db30ca8Sthorpej indicator.parent->w3.shadowThickness, 10088db30ca8Sthorpej indicator.parent->w3.bottomShadowColor, 10098db30ca8Sthorpej indicator.parent->w3.topShadowColor); 10108db30ca8Sthorpej } 10118db30ca8Sthorpej} 10128db30ca8Sthorpej 10138db30ca8Sthorpejvoid updateIndicatorElement(AppInfo *app, int i) 10148db30ca8Sthorpej{ 10158db30ca8Sthorpej DialogInfo *d = app->dialog; 10168db30ca8Sthorpej 10178db30ca8Sthorpej d->indicators[i].isLit = !(d->indicators[i].isLit); 10188db30ca8Sthorpej paintIndicator(app, d->dialogWindow, d->indicators[i]); 10198db30ca8Sthorpej} 10208db30ca8Sthorpej 10218db30ca8Sthorpejvoid updateIndicators(AppInfo *app, int condition) 10228db30ca8Sthorpej{ 10238db30ca8Sthorpej DialogInfo *d = app->dialog; 10248db30ca8Sthorpej 10258db30ca8Sthorpej if (condition > 0) { 10268db30ca8Sthorpej /* Move forward one. */ 10278db30ca8Sthorpej updateIndicatorElement(app, d->indicator.current); 10288db30ca8Sthorpej if (d->indicator.current < (d->indicator.count - 1)) { 10298db30ca8Sthorpej (d->indicator.current)++; 10308db30ca8Sthorpej } else { 10318db30ca8Sthorpej d->indicator.current = 0; 10328db30ca8Sthorpej } 10338db30ca8Sthorpej } else if (condition < 0) { 10348db30ca8Sthorpej /* Move backward one. */ 10358db30ca8Sthorpej if (d->indicator.current > 0) { 10368db30ca8Sthorpej (d->indicator.current)--; 10378db30ca8Sthorpej } else { 10388db30ca8Sthorpej d->indicator.current = d->indicator.count - 1; 10398db30ca8Sthorpej } 10408db30ca8Sthorpej updateIndicatorElement(app, d->indicator.current); 10418db30ca8Sthorpej } else { 10428db30ca8Sthorpej /* Erase them all. */ 10438db30ca8Sthorpej int i; 10448db30ca8Sthorpej 10458db30ca8Sthorpej for (i = 0; i < d->indicator.count; i++) { 10468db30ca8Sthorpej d->indicators[i].isLit = False; 10478db30ca8Sthorpej paintIndicator(app, d->dialogWindow, d->indicators[i]); 10488db30ca8Sthorpej } 10498db30ca8Sthorpej d->indicator.current = 0; 10508db30ca8Sthorpej } 10518db30ca8Sthorpej XSync(app->dpy, False); 10528db30ca8Sthorpej} 10538db30ca8Sthorpej 10548db30ca8Sthorpejvoid paintDialog(AppInfo *app) 10558db30ca8Sthorpej{ 10568db30ca8Sthorpej DialogInfo *d = app->dialog; 10578db30ca8Sthorpej Drawable draw = d->dialogWindow; 10588db30ca8Sthorpej int i; 10598db30ca8Sthorpej 10608db30ca8Sthorpej XSetForeground(app->dpy, app->fillGC, d->w3.w.background); 10618db30ca8Sthorpej XFillRectangle(app->dpy, draw, app->fillGC, 0, 0, 10628db30ca8Sthorpej d->w3.w.width, d->w3.w.height); 10638db30ca8Sthorpej if (d->w3.shadowThickness > 0) { 10648db30ca8Sthorpej draw_shaded_rectangle(app->dpy, draw, 0, 0, 10658db30ca8Sthorpej d->w3.w.width, d->w3.w.height, 10668db30ca8Sthorpej d->w3.shadowThickness, 10678db30ca8Sthorpej d->w3.topShadowColor, 10688db30ca8Sthorpej d->w3.bottomShadowColor); 10698db30ca8Sthorpej } 10708db30ca8Sthorpej paintLabel(app, draw, d->label); 10718db30ca8Sthorpej for (i = 0; i < d->indicator.count; i++) { 10728db30ca8Sthorpej paintIndicator(app, draw, d->indicators[i]); 10738db30ca8Sthorpej } 10748db30ca8Sthorpej paintButton(app, draw, d->okButton); 10758db30ca8Sthorpej paintButton(app, draw, d->cancelButton); 10768db30ca8Sthorpej XSync(app->dpy, False); 10778db30ca8Sthorpej} 10788db30ca8Sthorpej 1079c056561aSmbalmervoid performGrab(AppInfo *app, int grabType, char *grabTypeName, 1080c056561aSmbalmer Bool shouldGrab, Bool *isGrabbed) { 1081c056561aSmbalmer if ((!(shouldGrab)) || (*isGrabbed)) { 1082c056561aSmbalmer return; 1083c056561aSmbalmer } else if ((GRAB_KEYBOARD != grabType) && (GRAB_POINTER != grabType)) { 1084c056561aSmbalmer fprintf(stderr, "%s[%ld]: performGrab: invalid grab type (%d).\n", 1085c056561aSmbalmer app->appName, (long) app->pid, grabType); 10868db30ca8Sthorpej return; 10878db30ca8Sthorpej } else { 1088c056561aSmbalmer int status = GrabInvalidTime; /* keep gcc -Wall from complaining */ 1089c056561aSmbalmer unsigned int seconds = 0; 1090c056561aSmbalmer int helpful_message = 0; 1091c056561aSmbalmer /* keyboard and pointer */ 10928db30ca8Sthorpej Window grabWindow = app->dialog->dialogWindow; 10938db30ca8Sthorpej Bool ownerEvents = False; 10948db30ca8Sthorpej Bool pointerMode = GrabModeAsync; 10958db30ca8Sthorpej Bool keyboardMode = GrabModeAsync; 1096c056561aSmbalmer /* pointer only */ 1097c056561aSmbalmer unsigned int eventMask = ButtonPressMask | ButtonReleaseMask; 1098c056561aSmbalmer Window confineTo = None; 1099c056561aSmbalmer Cursor cursor = None; 1100c056561aSmbalmer 1101c056561aSmbalmer *isGrabbed = True; 1102c056561aSmbalmer 1103c056561aSmbalmer if (NULL == grabTypeName) { 1104c056561aSmbalmer fprintf(stderr, "%s[%ld]: performGrab: null grab type name.\n", 1105c056561aSmbalmer app->appName, (long) app->pid); 1106c056561aSmbalmer } 11078db30ca8Sthorpej 1108c056561aSmbalmer if (0 == app->grabFailTimeout) { 1109c056561aSmbalmer /* Ensure we try to perform the grab at least once. */ 1110c056561aSmbalmer app->grabFailTimeout = 1; 1111c056561aSmbalmer } 1112c056561aSmbalmer while (seconds < app->grabFailTimeout) { 1113c056561aSmbalmer XSync(app->dpy, False); 1114c056561aSmbalmer switch (grabType) { 1115c056561aSmbalmer case GRAB_KEYBOARD: 1116c056561aSmbalmer status = XGrabKeyboard(app->dpy, grabWindow, ownerEvents, 1117c056561aSmbalmer pointerMode, keyboardMode, CurrentTime); 1118c056561aSmbalmer break; 1119c056561aSmbalmer case GRAB_POINTER: 1120c056561aSmbalmer status = XGrabPointer(app->dpy, grabWindow, ownerEvents, 1121c056561aSmbalmer eventMask, pointerMode, keyboardMode, 1122c056561aSmbalmer confineTo, cursor, CurrentTime); 1123c056561aSmbalmer break; 1124c056561aSmbalmer } 1125c056561aSmbalmer XSync(app->dpy, False); 1126c056561aSmbalmer if (GrabSuccess == status) { 1127c056561aSmbalmer if (helpful_message) { 1128c056561aSmbalmer fprintf(stderr, "%s[%ld]: Got %s.\n", 1129c056561aSmbalmer app->appName, (long) app->pid, grabTypeName); 1130c056561aSmbalmer } 1131c056561aSmbalmer break; 1132c056561aSmbalmer } 1133c056561aSmbalmer if (!helpful_message) { 1134c056561aSmbalmer fprintf(stderr, "%s[%ld]: Trying to grab %s ...\n", 1135c056561aSmbalmer app->appName, (long) app->pid, grabTypeName); 1136c056561aSmbalmer helpful_message = 1; 1137c056561aSmbalmer } 1138c056561aSmbalmer seconds += app->grabRetryInterval; 1139c056561aSmbalmer sleep(app->grabRetryInterval); 1140c056561aSmbalmer } 11418db30ca8Sthorpej if (GrabSuccess != status) { 11428db30ca8Sthorpej char *reason = "reason unknown"; 11438db30ca8Sthorpej 11448db30ca8Sthorpej switch (status) { 11458db30ca8Sthorpej case AlreadyGrabbed: 1146c056561aSmbalmer reason = "someone else already has it"; 11478db30ca8Sthorpej break; 11488db30ca8Sthorpej case GrabFrozen: 1149c056561aSmbalmer reason = "someone else has frozen it"; 11508db30ca8Sthorpej break; 11518db30ca8Sthorpej case GrabInvalidTime: 11528db30ca8Sthorpej reason = "bad grab time [this shouldn't happen]"; 11538db30ca8Sthorpej break; 11548db30ca8Sthorpej case GrabNotViewable: 11558db30ca8Sthorpej reason = "grab not viewable [this shouldn't happen]"; 11568db30ca8Sthorpej break; 11578db30ca8Sthorpej } 1158c056561aSmbalmer fprintf(stderr, "%s[%ld]: Could not grab %s (%s)\n", 1159c056561aSmbalmer app->appName, (long) app->pid, grabTypeName, reason); 11608db30ca8Sthorpej exitApp(app, EXIT_STATUS_ERROR); 11618db30ca8Sthorpej } 11628db30ca8Sthorpej } 11638db30ca8Sthorpej} 1164c056561aSmbalmer 1165c056561aSmbalmer 1166c056561aSmbalmervoid grabKeyboard(AppInfo *app) 1167c056561aSmbalmer{ 1168c056561aSmbalmer performGrab(app, GRAB_KEYBOARD, "keyboard", app->grabKeyboard, 1169c056561aSmbalmer &(app->isKeyboardGrabbed)); 1170c056561aSmbalmer} 11718db30ca8Sthorpej 11728db30ca8Sthorpejvoid ungrabKeyboard(AppInfo *app) 11738db30ca8Sthorpej{ 11748db30ca8Sthorpej if (app->grabKeyboard) { 11758db30ca8Sthorpej XUngrabKeyboard(app->dpy, CurrentTime); 11768db30ca8Sthorpej } 11778db30ca8Sthorpej} 11788db30ca8Sthorpej 11798db30ca8Sthorpejvoid grabPointer(AppInfo *app) 11808db30ca8Sthorpej{ 1181c056561aSmbalmer performGrab(app, GRAB_POINTER, "pointer", app->grabPointer, 1182c056561aSmbalmer &(app->isPointerGrabbed)); 11838db30ca8Sthorpej} 11848db30ca8Sthorpej 11858db30ca8Sthorpejvoid ungrabPointer(AppInfo *app) 11868db30ca8Sthorpej{ 11878db30ca8Sthorpej if (app->grabPointer) { 11888db30ca8Sthorpej XUngrabPointer(app->dpy, CurrentTime); 11898db30ca8Sthorpej } 11908db30ca8Sthorpej} 11918db30ca8Sthorpej 11928db30ca8Sthorpejvoid grabServer(AppInfo *app) 11938db30ca8Sthorpej{ 11948db30ca8Sthorpej if ((!(app->grabServer)) || (app->isServerGrabbed)) { 11958db30ca8Sthorpej return; 11968db30ca8Sthorpej } else { 11978db30ca8Sthorpej app->isServerGrabbed = True; 11988db30ca8Sthorpej XSync(app->dpy, False); 11998db30ca8Sthorpej XGrabServer(app->dpy); 12008db30ca8Sthorpej XSync(app->dpy, False); 12018db30ca8Sthorpej } 12028db30ca8Sthorpej} 12038db30ca8Sthorpej 12048db30ca8Sthorpejvoid ungrabServer(AppInfo *app) 12058db30ca8Sthorpej{ 12068db30ca8Sthorpej if (app->grabServer) { 12078db30ca8Sthorpej XUngrabServer(app->dpy); 12088db30ca8Sthorpej } 12098db30ca8Sthorpej} 12108db30ca8Sthorpej 12118db30ca8Sthorpejvoid cleanUp(AppInfo *app) 12128db30ca8Sthorpej{ 1213c056561aSmbalmer cancelInputTimeout(app); 12148db30ca8Sthorpej XDestroyWindow(app->dpy, app->dialog->dialogWindow); 12158db30ca8Sthorpej destroyGCs(app); 12168db30ca8Sthorpej destroyDialog(app); 12178db30ca8Sthorpej if (app->buf) { 12188db30ca8Sthorpej memset(app->buf, 0, app->bufSize); 12198db30ca8Sthorpej } 12208db30ca8Sthorpej freeIf(app->buf); 12218db30ca8Sthorpej ungrabPointer(app); 12228db30ca8Sthorpej ungrabKeyboard(app); 12238db30ca8Sthorpej ungrabServer(app); 12248db30ca8Sthorpej} 12258db30ca8Sthorpej 12268db30ca8Sthorpejvoid exitApp(AppInfo *app, int exitCode) 12278db30ca8Sthorpej{ 12288db30ca8Sthorpej cleanUp(app); 12298db30ca8Sthorpej exit(exitCode); 12308db30ca8Sthorpej} 12318db30ca8Sthorpej 12328db30ca8Sthorpejvoid acceptAction(AppInfo *app) 12338db30ca8Sthorpej{ 12348db30ca8Sthorpej int status = append_to_buf(&(app->buf), &(app->bufSize), 12358db30ca8Sthorpej &(app->bufIndex), '\0'); 12368db30ca8Sthorpej if (APPEND_FAILURE == status) { 12378db30ca8Sthorpej cleanUp(app); 12388db30ca8Sthorpej outOfMemory(app, __LINE__); 12398db30ca8Sthorpej } 12408db30ca8Sthorpej fputs(app->buf, stdout); 12418db30ca8Sthorpej fputc('\n', stdout); 12428db30ca8Sthorpej exitApp(app, EXIT_STATUS_ACCEPT); 12438db30ca8Sthorpej} 12448db30ca8Sthorpej 12458db30ca8Sthorpejvoid cancelAction(AppInfo *app) 12468db30ca8Sthorpej{ 12478db30ca8Sthorpej exitApp(app, EXIT_STATUS_CANCEL); 12488db30ca8Sthorpej} 12498db30ca8Sthorpej 12508db30ca8Sthorpejvoid backspacePassphrase(AppInfo *app) 12518db30ca8Sthorpej{ 12528db30ca8Sthorpej if (0 >= app->bufIndex) { 12538db30ca8Sthorpej XBell(app->dpy, 0); 12548db30ca8Sthorpej return; 12558db30ca8Sthorpej } 12568db30ca8Sthorpej (app->bufIndex)--; 12578db30ca8Sthorpej updateIndicators(app, -1); 12588db30ca8Sthorpej} 12598db30ca8Sthorpej 12608db30ca8Sthorpejvoid erasePassphrase(AppInfo *app) 12618db30ca8Sthorpej{ 12628db30ca8Sthorpej if (0 >= app->bufIndex) { 12638db30ca8Sthorpej XBell(app->dpy, 0); 12648db30ca8Sthorpej return; 12658db30ca8Sthorpej } 12668db30ca8Sthorpej updateIndicators(app, 0); 12678db30ca8Sthorpej app->bufIndex = 0; 12688db30ca8Sthorpej} 12698db30ca8Sthorpej 12708db30ca8Sthorpejvoid addToPassphrase(AppInfo *app, char c) 12718db30ca8Sthorpej{ 12728db30ca8Sthorpej int status = append_to_buf(&(app->buf), &(app->bufSize), 12738db30ca8Sthorpej &(app->bufIndex), c); 12748db30ca8Sthorpej if (APPEND_FAILURE == status) { 12758db30ca8Sthorpej cleanUp(app); 12768db30ca8Sthorpej outOfMemory(app, __LINE__); 12778db30ca8Sthorpej } 12788db30ca8Sthorpej updateIndicators(app, 1); 12798db30ca8Sthorpej} 12808db30ca8Sthorpej 1281c056561aSmbalmervoid handleKeyPress(AppInfo *app, XEvent *event) 12828db30ca8Sthorpej{ 12838db30ca8Sthorpej char s[2]; 12848db30ca8Sthorpej int n; 12858db30ca8Sthorpej 1286c056561aSmbalmer if (event->xkey.send_event) { 12878db30ca8Sthorpej /* Pay no attention to synthetic key events. */ 12888db30ca8Sthorpej return; 12898db30ca8Sthorpej } 1290c056561aSmbalmer cancelInputTimeout(app); 1291c056561aSmbalmer n = XLookupString(&(event->xkey), s, 1, NULL, NULL); 12928db30ca8Sthorpej 12938db30ca8Sthorpej if (1 != n) { 12948db30ca8Sthorpej return; 12958db30ca8Sthorpej } 12968db30ca8Sthorpej s[1] = '\0'; 12978db30ca8Sthorpej switch (s[0]) { 12988db30ca8Sthorpej case '\010': 12998db30ca8Sthorpej case '\177': 13008db30ca8Sthorpej backspacePassphrase(app); 13018db30ca8Sthorpej break; 13028db30ca8Sthorpej case '\025': 13038db30ca8Sthorpej case '\030': 13048db30ca8Sthorpej erasePassphrase(app); 13058db30ca8Sthorpej break; 13068db30ca8Sthorpej case '\012': 13078db30ca8Sthorpej case '\015': 13088db30ca8Sthorpej acceptAction(app); 13098db30ca8Sthorpej break; 13108db30ca8Sthorpej case '\033': 13118db30ca8Sthorpej cancelAction(app); 13128db30ca8Sthorpej break; 13138db30ca8Sthorpej default: 13148db30ca8Sthorpej addToPassphrase(app, s[0]); 13158db30ca8Sthorpej break; 13168db30ca8Sthorpej } 13178db30ca8Sthorpej} 13188db30ca8Sthorpej 1319c056561aSmbalmerBool eventIsInsideButton(AppInfo *app, XEvent *event, ButtonInfo button) 13208db30ca8Sthorpej{ 1321c056561aSmbalmer /* 'gcc -Wall' complains about 'app' being an unused parameter. 1322c056561aSmbalmer * Tough. We might want to use it later, and then we don't have 1323c056561aSmbalmer * to change it in each place it's called. Performance won't suffer. 1324c056561aSmbalmer */ 13258db30ca8Sthorpej int status = False; 1326c056561aSmbalmer int x, y; 13278db30ca8Sthorpej 1328c056561aSmbalmer switch(event->type) { 1329c056561aSmbalmer case ButtonPress: 1330c056561aSmbalmer case ButtonRelease: 1331c056561aSmbalmer x = event->xbutton.x; 1332c056561aSmbalmer y = event->xbutton.y; 1333c056561aSmbalmer break; 1334c056561aSmbalmer case MotionNotify: 1335c056561aSmbalmer x = event->xmotion.x; 1336c056561aSmbalmer y = event->xmotion.y; 1337c056561aSmbalmer break; 1338c056561aSmbalmer default: 1339c056561aSmbalmer return(False); 1340c056561aSmbalmer } 1341c056561aSmbalmer if ((x >= (button.w3.w.x + button.w3.borderWidth)) && 1342c056561aSmbalmer (x < (button.w3.w.x + button.w3.w.width - 1343c056561aSmbalmer (2 * button.w3.borderWidth))) && 1344c056561aSmbalmer (y >= (button.w3.w.y + button.w3.borderWidth)) && 1345c056561aSmbalmer (y < (button.w3.w.y + button.w3.w.height - 1346c056561aSmbalmer (2 * button.w3.borderWidth)))) { 13478db30ca8Sthorpej status = True; 13488db30ca8Sthorpej } 13498db30ca8Sthorpej return(status); 13508db30ca8Sthorpej} 13518db30ca8Sthorpej 1352c056561aSmbalmervoid handleButtonPress(AppInfo *app, XEvent *event) 13538db30ca8Sthorpej{ 13548db30ca8Sthorpej DialogInfo *d = app->dialog; 1355c056561aSmbalmer 1356c056561aSmbalmer cancelInputTimeout(app); 1357c056561aSmbalmer if (event->xbutton.button != Button1) { 13588db30ca8Sthorpej return; 13598db30ca8Sthorpej } 13608db30ca8Sthorpej if (ButtonPress == event->type) { 13618db30ca8Sthorpej if (eventIsInsideButton(app, event, d->okButton)) { 13628db30ca8Sthorpej d->pressedButton = OK_BUTTON; 13638db30ca8Sthorpej d->okButton.pressed = True; 13648db30ca8Sthorpej paintButton(app, d->dialogWindow, d->okButton); 13658db30ca8Sthorpej } else if (eventIsInsideButton(app, event, d->cancelButton)) { 13668db30ca8Sthorpej d->pressedButton = CANCEL_BUTTON; 13678db30ca8Sthorpej d->cancelButton.pressed = True; 13688db30ca8Sthorpej paintButton(app, d->dialogWindow, d->cancelButton); 13698db30ca8Sthorpej } else { 13708db30ca8Sthorpej d->pressedButton = NO_BUTTON; 13718db30ca8Sthorpej } 13728db30ca8Sthorpej } else if (ButtonRelease == event->type) { 13738db30ca8Sthorpej if (OK_BUTTON == d->pressedButton) { 13748db30ca8Sthorpej if (eventIsInsideButton(app, event, d->okButton)) { 13758db30ca8Sthorpej acceptAction(app); 13768db30ca8Sthorpej } else { 1377c056561aSmbalmer if (d->okButton.pressed) { 1378c056561aSmbalmer d->okButton.pressed = False; 1379c056561aSmbalmer paintButton(app, d->dialogWindow, d->okButton); 1380c056561aSmbalmer } 13818db30ca8Sthorpej } 13828db30ca8Sthorpej } else if (CANCEL_BUTTON == d->pressedButton) { 13838db30ca8Sthorpej if (eventIsInsideButton(app, event, d->cancelButton)) { 13848db30ca8Sthorpej cancelAction(app); 13858db30ca8Sthorpej } else { 1386c056561aSmbalmer if (d->cancelButton.pressed) { 1387c056561aSmbalmer d->cancelButton.pressed = False; 1388c056561aSmbalmer paintButton(app, d->dialogWindow, d->cancelButton); 1389c056561aSmbalmer } 1390c056561aSmbalmer } 1391c056561aSmbalmer } 1392c056561aSmbalmer d->pressedButton = NO_BUTTON; 1393c056561aSmbalmer } 1394c056561aSmbalmer} 1395c056561aSmbalmer 1396c056561aSmbalmervoid handlePointerMotion(AppInfo *app, XEvent *event) 1397c056561aSmbalmer{ 1398c056561aSmbalmer DialogInfo *d = app->dialog; 1399c056561aSmbalmer 1400c056561aSmbalmer if (NO_BUTTON == d->pressedButton) { 1401c056561aSmbalmer return; 1402c056561aSmbalmer } else if (OK_BUTTON == d->pressedButton) { 1403c056561aSmbalmer if (eventIsInsideButton(app, event, d->okButton)) { 1404c056561aSmbalmer if (!(d->okButton.pressed)) { 1405c056561aSmbalmer d->okButton.pressed = True; 1406c056561aSmbalmer paintButton(app, d->dialogWindow, d->okButton); 1407c056561aSmbalmer } 1408c056561aSmbalmer } else { 1409c056561aSmbalmer if (d->okButton.pressed) { 1410c056561aSmbalmer d->okButton.pressed = False; 1411c056561aSmbalmer paintButton(app, d->dialogWindow, d->okButton); 1412c056561aSmbalmer } 1413c056561aSmbalmer } 1414c056561aSmbalmer } else if (CANCEL_BUTTON == d->pressedButton) { 1415c056561aSmbalmer if (eventIsInsideButton(app, event, d->cancelButton)) { 1416c056561aSmbalmer if (!(d->cancelButton.pressed)) { 1417c056561aSmbalmer d->cancelButton.pressed = True; 1418c056561aSmbalmer paintButton(app, d->dialogWindow, d->cancelButton); 1419c056561aSmbalmer } 1420c056561aSmbalmer } else { 1421c056561aSmbalmer if (d->cancelButton.pressed) { 14228db30ca8Sthorpej d->cancelButton.pressed = False; 14238db30ca8Sthorpej paintButton(app, d->dialogWindow, d->cancelButton); 14248db30ca8Sthorpej } 14258db30ca8Sthorpej } 1426c056561aSmbalmer } 1427c056561aSmbalmer} 1428c056561aSmbalmer 1429c056561aSmbalmervoid handleInputTimeout(XtPointer data, XtIntervalId *timerId) 1430c056561aSmbalmer{ 1431c056561aSmbalmer /* 'gcc -Wall' complains about 'timerId' being an unused parameter. 1432c056561aSmbalmer * Tough. Xt forces us to have it here. Like it. 1433c056561aSmbalmer */ 1434c056561aSmbalmer AppInfo *app = (AppInfo *) data; 1435c056561aSmbalmer if (app->inputTimeoutActive) { 1436c056561aSmbalmer app->inputTimeoutActive = False; 1437c056561aSmbalmer fprintf(stderr, "%s[%ld]: *Yawn*...timed out after %lu seconds.\n", 1438c056561aSmbalmer app->appName, (long) app->pid, (app->inputTimeout / 1000)); 1439c056561aSmbalmer exitApp(app, EXIT_STATUS_TIMEOUT); 1440c056561aSmbalmer } 1441c056561aSmbalmer} 1442c056561aSmbalmer 1443c056561aSmbalmervoid cancelInputTimeout(AppInfo *app) 1444c056561aSmbalmer{ 1445c056561aSmbalmer if (app->inputTimeoutActive) { 1446c056561aSmbalmer app->inputTimeoutActive = False; 1447c056561aSmbalmer XtRemoveTimeOut(app->inputTimeoutTimerId); 14488db30ca8Sthorpej } 14498db30ca8Sthorpej} 14508db30ca8Sthorpej 14518db30ca8Sthorpejint main(int argc, char **argv) 14528db30ca8Sthorpej{ 14538db30ca8Sthorpej AppInfo app; 14548db30ca8Sthorpej XEvent event; 1455c056561aSmbalmer XineramaScreenInfo *screens; 1456c056561aSmbalmer int nscreens; 14578db30ca8Sthorpej 14588db30ca8Sthorpej memset(&app, 0, sizeof(app)); 14598db30ca8Sthorpej 14608db30ca8Sthorpej progclass = "SshAskpass"; 14618db30ca8Sthorpej app.toplevelShell = XtAppInitialize(&(app.appContext), progclass, 14628db30ca8Sthorpej NULL, 0, &argc, argv, 14638db30ca8Sthorpej defaults, NULL, 0); 1464c056561aSmbalmer app.argc = argc; 1465c056561aSmbalmer app.argv = argv; 14668db30ca8Sthorpej app.dpy = XtDisplay(app.toplevelShell); 14678db30ca8Sthorpej app.screen = DefaultScreenOfDisplay(app.dpy); 14688db30ca8Sthorpej app.rootWindow = RootWindowOfScreen(app.screen); 14698db30ca8Sthorpej app.black = BlackPixel(app.dpy, DefaultScreen(app.dpy)); 14708db30ca8Sthorpej app.white = WhitePixel(app.dpy, DefaultScreen(app.dpy)); 14718db30ca8Sthorpej app.colormap = DefaultColormapOfScreen(app.screen); 14728db30ca8Sthorpej app.resourceDb = XtDatabase(app.dpy); 14738db30ca8Sthorpej XtGetApplicationNameAndClass(app.dpy, &progname, &progclass); 14748db30ca8Sthorpej app.appName = progname; 14758db30ca8Sthorpej app.appClass = progclass; 14768db30ca8Sthorpej /* For resources.c. */ 14778db30ca8Sthorpej db = app.resourceDb; 1478c056561aSmbalmer 1479c056561aSmbalmer /* Seconds after which keyboard/pointer grab fail. */ 1480c056561aSmbalmer app.grabFailTimeout = 5; 1481c056561aSmbalmer /* Number of seconds to wait between grab attempts. */ 1482c056561aSmbalmer app.grabRetryInterval = 1; 1483c056561aSmbalmer 1484c056561aSmbalmer app.pid = getpid(); 14858db30ca8Sthorpej 14868db30ca8Sthorpej { 14878db30ca8Sthorpej struct rlimit resourceLimit; 14888db30ca8Sthorpej int status; 14898db30ca8Sthorpej 14908db30ca8Sthorpej status = getrlimit(RLIMIT_CORE, &resourceLimit); 14918db30ca8Sthorpej if (-1 == status) { 1492c056561aSmbalmer fprintf(stderr, "%s[%ld]: getrlimit failed (%s)\n", app.appName, 1493c056561aSmbalmer (long) app.pid, strerror(errno)); 14948db30ca8Sthorpej exit(EXIT_STATUS_ERROR); 14958db30ca8Sthorpej } 14968db30ca8Sthorpej resourceLimit.rlim_cur = 0; 14978db30ca8Sthorpej status = setrlimit(RLIMIT_CORE, &resourceLimit); 14988db30ca8Sthorpej if (-1 == status) { 1499c056561aSmbalmer fprintf(stderr, "%s[%ld]: setrlimit failed (%s)\n", app.appName, 1500c056561aSmbalmer (long) app.pid, strerror(errno)); 15018db30ca8Sthorpej exit(EXIT_STATUS_ERROR); 15028db30ca8Sthorpej } 15038db30ca8Sthorpej } 15048db30ca8Sthorpej 1505c056561aSmbalmer app.screen_width = WidthOfScreen(app.screen); 1506c056561aSmbalmer app.screen_height = HeightOfScreen(app.screen); 1507c056561aSmbalmer if (XineramaIsActive(app.dpy) && 1508c056561aSmbalmer (screens = XineramaQueryScreens(app.dpy, &nscreens)) != NULL && 1509c056561aSmbalmer nscreens) { 1510c056561aSmbalmer app.screen_width = screens[0].width; 1511c056561aSmbalmer app.screen_height = screens[0].height; 1512c056561aSmbalmer XFree(screens); 1513c056561aSmbalmer } 1514c056561aSmbalmer 1515c056561aSmbalmer app.xResolution = 1516c056561aSmbalmer app.screen_width * 1000 / WidthMMOfScreen(app.screen); 1517c056561aSmbalmer app.yResolution = 1518c056561aSmbalmer app.screen_height * 1000 / HeightMMOfScreen(app.screen); 1519c056561aSmbalmer 15208db30ca8Sthorpej createDialog(&app); 15218db30ca8Sthorpej createGCs(&app); 1522c056561aSmbalmer 1523c056561aSmbalmer app.eventMask = 0; 1524c056561aSmbalmer app.eventMask |= ExposureMask; 1525c056561aSmbalmer app.eventMask |= ButtonPressMask; 1526c056561aSmbalmer app.eventMask |= ButtonReleaseMask; 1527c056561aSmbalmer app.eventMask |= Button1MotionMask; 1528c056561aSmbalmer app.eventMask |= KeyPressMask; 1529c056561aSmbalmer 15308db30ca8Sthorpej createDialogWindow(&app); 15318db30ca8Sthorpej 15328db30ca8Sthorpej XMapWindow(app.dpy, app.dialog->dialogWindow); 1533c056561aSmbalmer if (app.inputTimeout > 0) { 1534c056561aSmbalmer app.inputTimeoutActive = True; 1535c056561aSmbalmer app.inputTimeoutTimerId = 1536c056561aSmbalmer XtAppAddTimeOut(app.appContext, app.inputTimeout, 1537c056561aSmbalmer handleInputTimeout, (XtPointer) &app); 1538c056561aSmbalmer } 1539c056561aSmbalmer 15408db30ca8Sthorpej 15418db30ca8Sthorpej while(True) { 1542c056561aSmbalmer XtAppNextEvent(app.appContext, &event); 15438db30ca8Sthorpej switch (event.type) { 15448db30ca8Sthorpej case Expose: 15458db30ca8Sthorpej grabServer(&app); 15468db30ca8Sthorpej grabKeyboard(&app); 15478db30ca8Sthorpej grabPointer(&app); 15488db30ca8Sthorpej if (event.xexpose.count) { 15498db30ca8Sthorpej break; 15508db30ca8Sthorpej } 15518db30ca8Sthorpej paintDialog(&app); 15528db30ca8Sthorpej break; 15538db30ca8Sthorpej case ButtonPress: 15548db30ca8Sthorpej case ButtonRelease: 1555c056561aSmbalmer handleButtonPress(&app, &event); 15568db30ca8Sthorpej break; 1557c056561aSmbalmer case MotionNotify: 1558c056561aSmbalmer handlePointerMotion(&app, &event); 15598db30ca8Sthorpej case KeyPress: 1560c056561aSmbalmer handleKeyPress(&app, &event); 15618db30ca8Sthorpej break; 15628db30ca8Sthorpej case ClientMessage: 15638db30ca8Sthorpej if ((32 == event.xclient.format) && 1564c056561aSmbalmer ((unsigned long) event.xclient.data.l[0] == 1565c056561aSmbalmer app.wmDeleteWindowAtom)) { 15668db30ca8Sthorpej cancelAction(&app); 15678db30ca8Sthorpej } 15688db30ca8Sthorpej break; 15698db30ca8Sthorpej default: 15708db30ca8Sthorpej break; 15718db30ca8Sthorpej } 15728db30ca8Sthorpej } 15738db30ca8Sthorpej 1574c056561aSmbalmer fprintf(stderr, "%s[%ld]: This should not happen.\n", app.appName, 1575c056561aSmbalmer (long) app.pid); 15768db30ca8Sthorpej return(EXIT_STATUS_ANOMALY); 15778db30ca8Sthorpej} 15788db30ca8Sthorpej 1579