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