1 | /* x11-ssh-askpass.c: A generic X11-based password dialog for OpenSSH. |
---|
2 | * created 1999-Nov-17 03:40 Jim Knoble <jmknoble@pobox.com> |
---|
3 | * autodate: 2001-Sep-16 18:08 |
---|
4 | * |
---|
5 | * by Jim Knoble <jmknoble@pobox.com> |
---|
6 | * Copyright (C) 1999,2000,2001 Jim Knoble |
---|
7 | * |
---|
8 | * Disclaimer: |
---|
9 | * |
---|
10 | * The software is provided "as is", without warranty of any kind, |
---|
11 | * express or implied, including but not limited to the warranties of |
---|
12 | * merchantability, fitness for a particular purpose and |
---|
13 | * noninfringement. In no event shall the author(s) be liable for any |
---|
14 | * claim, damages or other liability, whether in an action of |
---|
15 | * contract, tort or otherwise, arising from, out of or in connection |
---|
16 | * with the software or the use or other dealings in the software. |
---|
17 | * |
---|
18 | * Portions of this code are distantly derived from code in xscreensaver |
---|
19 | * by Jamie Zawinski <jwz@jwz.org>. That code says: |
---|
20 | * |
---|
21 | * --------8<------------------------------------------------8<-------- |
---|
22 | * xscreensaver, Copyright (c) 1991-1999 Jamie Zawinski <jwz@jwz.org> |
---|
23 | * |
---|
24 | * Permission to use, copy, modify, distribute, and sell this software and its |
---|
25 | * documentation for any purpose is hereby granted without fee, provided that |
---|
26 | * the above copyright notice appear in all copies and that both that |
---|
27 | * copyright notice and this permission notice appear in supporting |
---|
28 | * documentation. No representations are made about the suitability of this |
---|
29 | * software for any purpose. It is provided "as is" without express or |
---|
30 | * implied warranty. |
---|
31 | * --------8<------------------------------------------------8<-------- |
---|
32 | * |
---|
33 | * The remainder of this code falls under the same permissions and |
---|
34 | * provisions as those of the xscreensaver code. |
---|
35 | */ |
---|
36 | |
---|
37 | #include <ctype.h> |
---|
38 | #include <stdio.h> |
---|
39 | #include <stdlib.h> |
---|
40 | #include <string.h> |
---|
41 | |
---|
42 | /* For (get|set)rlimit() ... */ |
---|
43 | #include <sys/time.h> |
---|
44 | #include <sys/resource.h> |
---|
45 | /* ... end */ |
---|
46 | /* For (get|set)rlimit(), sleep(), and getpid() ... */ |
---|
47 | #include <unistd.h> |
---|
48 | /* ... end */ |
---|
49 | |
---|
50 | /* For errno ... */ |
---|
51 | #include <errno.h> |
---|
52 | /* ... end */ |
---|
53 | |
---|
54 | #include <X11/Xlib.h> |
---|
55 | #include <X11/Intrinsic.h> |
---|
56 | #include <X11/Shell.h> |
---|
57 | #include <X11/Xos.h> |
---|
58 | #include "dynlist.h" |
---|
59 | #include "drawing.h" |
---|
60 | #include "resources.h" |
---|
61 | #include "x11-ssh-askpass.h" |
---|
62 | |
---|
63 | #undef MAX |
---|
64 | #define MAX(a,b) (((a) > (b)) ? (a) : (b)) |
---|
65 | |
---|
66 | char *progname = NULL; |
---|
67 | char *progclass = NULL; |
---|
68 | XrmDatabase db = 0; |
---|
69 | |
---|
70 | static char *defaults[] = { |
---|
71 | #include "SshAskpass_ad.h" |
---|
72 | 0 |
---|
73 | }; |
---|
74 | |
---|
75 | void outOfMemory(AppInfo *app, int line) |
---|
76 | { |
---|
77 | fprintf(stderr, "%s[%ld]: Aaahhh! I ran out of memory at line %d.\n", |
---|
78 | app->appName, (long) app->pid, line); |
---|
79 | exit(EXIT_STATUS_NO_MEMORY); |
---|
80 | } |
---|
81 | |
---|
82 | void freeIf(void *p) |
---|
83 | { |
---|
84 | if (p) { |
---|
85 | free(p); |
---|
86 | } |
---|
87 | } |
---|
88 | |
---|
89 | void freeFontIf(AppInfo *app, XFontStruct *f) |
---|
90 | { |
---|
91 | if (f) { |
---|
92 | XFreeFont(app->dpy, f); |
---|
93 | } |
---|
94 | } |
---|
95 | |
---|
96 | XFontStruct *getFontResource(AppInfo *app, char *instanceName, char *className) |
---|
97 | { |
---|
98 | char *fallbackFont = "fixed"; |
---|
99 | |
---|
100 | XFontStruct *f = NULL; |
---|
101 | char *s = get_string_resource(instanceName, className); |
---|
102 | f = XLoadQueryFont(app->dpy, (s ? s : fallbackFont)); |
---|
103 | if (!f) { |
---|
104 | f = XLoadQueryFont(app->dpy, fallbackFont); |
---|
105 | } |
---|
106 | if (s) { |
---|
107 | free(s); |
---|
108 | } |
---|
109 | return(f); |
---|
110 | } |
---|
111 | |
---|
112 | char *getStringResourceWithDefault(char *instanceName, char *className, |
---|
113 | char *defaultText) |
---|
114 | { |
---|
115 | char *s = get_string_resource(instanceName, className); |
---|
116 | if (!s) { |
---|
117 | if (!defaultText) { |
---|
118 | s = strdup(""); |
---|
119 | } else { |
---|
120 | s = strdup(defaultText); |
---|
121 | } |
---|
122 | } |
---|
123 | return(s); |
---|
124 | } |
---|
125 | |
---|
126 | unsigned int getUnsignedIntegerResource(AppInfo *app, char *instanceName, |
---|
127 | char *className, |
---|
128 | unsigned int defaultValue) |
---|
129 | { |
---|
130 | int n; |
---|
131 | unsigned int value; |
---|
132 | char c; |
---|
133 | char *s = get_string_resource(instanceName, className); |
---|
134 | char *cp = s; |
---|
135 | |
---|
136 | if (NULL == s) { |
---|
137 | return(defaultValue); |
---|
138 | } |
---|
139 | while ((*cp) && isspace(*cp)) { |
---|
140 | /* Skip whitespace. */ |
---|
141 | cp++; |
---|
142 | } |
---|
143 | if (*cp) { |
---|
144 | if (('0' == cp[0]) && cp[1]) { |
---|
145 | if (('x' == cp[1]) || ('X' == cp[1])) { |
---|
146 | /* Hex */ |
---|
147 | n = sscanf(cp + 2, "%x %c", &value, &c); |
---|
148 | } else { |
---|
149 | /* Octal */ |
---|
150 | n = sscanf(cp + 1, "%o %c", &value, &c); |
---|
151 | } |
---|
152 | if (1 == n) { |
---|
153 | free(s); |
---|
154 | return(value); |
---|
155 | } |
---|
156 | } else { |
---|
157 | /* Unsigned Decimal */ |
---|
158 | n = sscanf(cp, "%u %c", &value, &c); |
---|
159 | if (1 == n) { |
---|
160 | free(s); |
---|
161 | return(value); |
---|
162 | } |
---|
163 | } |
---|
164 | } |
---|
165 | /* If we get here, no conversion succeeded. */ |
---|
166 | fprintf(stderr, "%s[%ld]: invalid value '%s' for %s.\n", |
---|
167 | app->appName, (long) app->pid, s, instanceName); |
---|
168 | free(s); |
---|
169 | return(defaultValue); |
---|
170 | } |
---|
171 | |
---|
172 | /* Default resolution is 75 dots/inch. 1 in = 2.54 cm. */ |
---|
173 | #define DefaultResolution ((75 * 10000) / 254) |
---|
174 | long getResolutionResource(AppInfo *app, char *instanceName, char *className, |
---|
175 | char *defaultResolutionSpec) |
---|
176 | { |
---|
177 | char units[3]; |
---|
178 | char *s; |
---|
179 | int n; |
---|
180 | long resolution; |
---|
181 | unsigned int i; |
---|
182 | |
---|
183 | memset(units, 0, sizeof(units)); |
---|
184 | s = getStringResourceWithDefault(instanceName, className, |
---|
185 | defaultResolutionSpec); |
---|
186 | /* NOTE: The width of the %s format must be one less than |
---|
187 | * the length of the units[] array above! |
---|
188 | */ |
---|
189 | n = sscanf(s, "%ld / %2s", &resolution, units); |
---|
190 | if (n != 2) { |
---|
191 | fprintf(stderr, "%s[%ld]: invalid value '%s' for %s.\n", |
---|
192 | app->appName, (long) app->pid, s, instanceName); |
---|
193 | resolution = DefaultResolution; |
---|
194 | } else { |
---|
195 | if (resolution < 0) { |
---|
196 | /* Resolution specifications should not be negative. */ |
---|
197 | resolution = -(resolution); |
---|
198 | } |
---|
199 | for (i = 0; i < (sizeof(units) - 1); i++) { |
---|
200 | units[i] = tolower(units[i]); |
---|
201 | } |
---|
202 | if ((0 == strcmp(units, "in")) || |
---|
203 | (0 == strcmp(units, "i")) || |
---|
204 | (0 == strcmp(units, "\""))) { |
---|
205 | /* dots/inch */ |
---|
206 | resolution = resolution * 10000 / 254; |
---|
207 | } else if ((0 == strcmp(units, "m")) || |
---|
208 | (0 == strcmp(units, "me"))) { |
---|
209 | /* dots/meter; no conversion necessary */ |
---|
210 | ; |
---|
211 | } else { |
---|
212 | /* some unit we don't recognize; cringe and stare at the floor */ |
---|
213 | resolution = DefaultResolution; |
---|
214 | } |
---|
215 | } |
---|
216 | return(resolution); |
---|
217 | } |
---|
218 | #undef DefaultResolution |
---|
219 | |
---|
220 | void calcTextObjectExtents(TextObject *t, XFontStruct *font) { |
---|
221 | if ((!t) || (!(t->text))) { |
---|
222 | return; |
---|
223 | } |
---|
224 | t->textLength = strlen(t->text); |
---|
225 | XTextExtents(font, t->text, t->textLength, &(t->direction), |
---|
226 | &(t->ascent), &(t->descent), &(t->overall)); |
---|
227 | } |
---|
228 | |
---|
229 | void calcLabelTextExtents(LabelInfo *label) |
---|
230 | { |
---|
231 | TextObject *t; |
---|
232 | |
---|
233 | if ((!label) || (!(label->fullText)) || (!(label->font))) { |
---|
234 | return; |
---|
235 | } |
---|
236 | t = label->multiText; |
---|
237 | while (NULL != t) { |
---|
238 | calcTextObjectExtents(t, label->font); |
---|
239 | label->w.height += (t->ascent + t->descent); |
---|
240 | if (label->w.width < t->overall.width) { |
---|
241 | label->w.width = t->overall.width; |
---|
242 | } |
---|
243 | t = t->next; |
---|
244 | } |
---|
245 | } |
---|
246 | |
---|
247 | void calcTotalButtonExtents(ButtonInfo *button) |
---|
248 | { |
---|
249 | if (!button) { |
---|
250 | return; |
---|
251 | } |
---|
252 | button->w3.w.width = (button->w3.interiorWidth + |
---|
253 | (2 * button->w3.shadowThickness)); |
---|
254 | button->w3.w.width += (2 * button->w3.borderWidth); |
---|
255 | button->w3.w.height = (button->w3.interiorHeight + |
---|
256 | (2 * button->w3.shadowThickness)); |
---|
257 | button->w3.w.height += (2 * button->w3.borderWidth); |
---|
258 | } |
---|
259 | |
---|
260 | void calcButtonExtents(ButtonInfo *button) |
---|
261 | { |
---|
262 | if (!button) { |
---|
263 | return; |
---|
264 | } |
---|
265 | calcLabelTextExtents(&(button->label)); |
---|
266 | button->w3.interiorWidth = (button->label.w.width + |
---|
267 | (2 * button->w3.horizontalSpacing)); |
---|
268 | button->w3.interiorHeight = (button->label.w.height + |
---|
269 | (2 * button->w3.verticalSpacing)); |
---|
270 | calcTotalButtonExtents(button); |
---|
271 | } |
---|
272 | |
---|
273 | void balanceButtonExtents(ButtonInfo *button1, ButtonInfo *button2) |
---|
274 | { |
---|
275 | if ((!button1) || (!button2)) { |
---|
276 | return; |
---|
277 | } |
---|
278 | button1->w3.interiorWidth = button2->w3.interiorWidth = |
---|
279 | MAX(button1->w3.interiorWidth, button2->w3.interiorWidth); |
---|
280 | button1->w3.interiorHeight = button2->w3.interiorHeight = |
---|
281 | MAX(button1->w3.interiorHeight, button2->w3.interiorHeight); |
---|
282 | calcTotalButtonExtents(button1); |
---|
283 | calcTotalButtonExtents(button2); |
---|
284 | } |
---|
285 | |
---|
286 | void calcButtonLabelPosition(ButtonInfo *button) |
---|
287 | { |
---|
288 | if (!button) { |
---|
289 | return; |
---|
290 | } |
---|
291 | button->label.w.x = button->w3.w.x + |
---|
292 | ((button->w3.w.width - button->label.w.width) / 2); |
---|
293 | button->label.w.y = button->w3.w.y + |
---|
294 | ((button->w3.w.height - button->label.w.height) / 2); |
---|
295 | } |
---|
296 | |
---|
297 | Dimension scaleXDimension(AppInfo *app, Dimension unscaled) |
---|
298 | { |
---|
299 | Dimension scaled; |
---|
300 | |
---|
301 | if (((app->defaultXResolution < app->xResolution) && |
---|
302 | ((app->defaultXResolution + app->xFuzz) < app->xResolution)) || |
---|
303 | ((app->xResolution < app->defaultXResolution) && |
---|
304 | ((app->xResolution + app->xFuzz) < app->defaultXResolution))) { |
---|
305 | scaled = (unscaled * app->xResolution) / app->defaultXResolution; |
---|
306 | } else { |
---|
307 | scaled = unscaled; |
---|
308 | } |
---|
309 | return(scaled); |
---|
310 | } |
---|
311 | |
---|
312 | Dimension scaleYDimension(AppInfo *app, Dimension unscaled) |
---|
313 | { |
---|
314 | Dimension scaled; |
---|
315 | |
---|
316 | if (((app->defaultYResolution < app->yResolution) && |
---|
317 | ((app->defaultYResolution + app->yFuzz) < app->yResolution)) || |
---|
318 | ((app->yResolution < app->defaultYResolution) && |
---|
319 | ((app->yResolution + app->yFuzz) < app->defaultYResolution))) { |
---|
320 | scaled = (unscaled * app->yResolution) / app->defaultYResolution; |
---|
321 | } else { |
---|
322 | scaled = unscaled; |
---|
323 | } |
---|
324 | return(scaled); |
---|
325 | } |
---|
326 | |
---|
327 | /* Assumes 's' is non-NULL. */ |
---|
328 | TextObject *createTextObject(AppInfo *app, char *s) |
---|
329 | { |
---|
330 | TextObject *t = malloc(sizeof(*t)); |
---|
331 | if (NULL == t) { |
---|
332 | outOfMemory(app, __LINE__); |
---|
333 | } |
---|
334 | memset(t, 0, sizeof(*t)); |
---|
335 | if (('\n' == *s) || ('\0' == *s)) { |
---|
336 | t->text = " "; |
---|
337 | } else { |
---|
338 | t->text = s; |
---|
339 | } |
---|
340 | return(t); |
---|
341 | } |
---|
342 | |
---|
343 | /* Assumes 'label' object exists and is zeroed. */ |
---|
344 | void createLabel(AppInfo *app, char *text, LabelInfo *label) |
---|
345 | { |
---|
346 | char *substring; |
---|
347 | TextObject *t; |
---|
348 | |
---|
349 | if ((!app) || (!text)) { |
---|
350 | return; |
---|
351 | } |
---|
352 | label->fullText = strdup(text); |
---|
353 | label->multiText = createTextObject(app, label->fullText); |
---|
354 | t = label->multiText; |
---|
355 | substring = strchr(label->fullText, '\n'); |
---|
356 | while (NULL != substring) { |
---|
357 | *(substring++) = '\0'; |
---|
358 | t->next = createTextObject(app, substring); |
---|
359 | if (t->next) { |
---|
360 | t = t->next; |
---|
361 | } |
---|
362 | substring = strchr(substring, '\n'); |
---|
363 | } |
---|
364 | } |
---|
365 | |
---|
366 | void createDialog(AppInfo *app) |
---|
367 | { |
---|
368 | DialogInfo *d; |
---|
369 | char *labelText; |
---|
370 | |
---|
371 | if (app->dialog) { |
---|
372 | return; |
---|
373 | } |
---|
374 | d = malloc(sizeof(*d)); |
---|
375 | if (NULL == d) { |
---|
376 | outOfMemory(app, __LINE__); |
---|
377 | } |
---|
378 | memset(d, 0, sizeof(*d)); |
---|
379 | |
---|
380 | app->grabKeyboard = |
---|
381 | get_boolean_resource("grabKeyboard", "GrabKeyboard", True); |
---|
382 | app->grabPointer = |
---|
383 | get_boolean_resource("grabPointer", "GrabPointer", False); |
---|
384 | app->grabServer = |
---|
385 | get_boolean_resource("grabServer", "GrabServer", False); |
---|
386 | |
---|
387 | /* inputTimeout resource specified in seconds for easy human interface. |
---|
388 | * Convert to milliseconds here. |
---|
389 | */ |
---|
390 | app->inputTimeout = (unsigned long) 1000 * |
---|
391 | getUnsignedIntegerResource(app, "inputTimeout", "InputTimeout", 0); |
---|
392 | |
---|
393 | app->defaultXResolution = |
---|
394 | getResolutionResource(app, "defaultXResolution", "DefaultXResolution", |
---|
395 | "75/in"); |
---|
396 | app->defaultYResolution = |
---|
397 | getResolutionResource(app, "defaultYResolution", "DefaultYResolution", |
---|
398 | "75/in"); |
---|
399 | app->xFuzz = |
---|
400 | getResolutionResource(app, "xResolutionFuzz", "XResolutionFuzz", "20/in"); |
---|
401 | app->yFuzz = |
---|
402 | getResolutionResource(app, "yResolutionFuzz", "YResolutionFuzz", "20/in"); |
---|
403 | |
---|
404 | d->title = |
---|
405 | getStringResourceWithDefault("dialog.title", "Dialog.Title", |
---|
406 | "OpenSSH Authentication Passphrase Request"); |
---|
407 | d->w3.w.foreground = |
---|
408 | get_pixel_resource("foreground", "Foreground", |
---|
409 | app->dpy, app->colormap, app->black); |
---|
410 | d->w3.w.background = |
---|
411 | get_pixel_resource("background", "Background", |
---|
412 | app->dpy, app->colormap, app->white); |
---|
413 | d->w3.topShadowColor = |
---|
414 | get_pixel_resource("topShadowColor", "TopShadowColor", |
---|
415 | app->dpy, app->colormap, app->white); |
---|
416 | d->w3.bottomShadowColor = |
---|
417 | get_pixel_resource("bottomShadowColor", "BottomShadowColor", |
---|
418 | app->dpy, app->colormap, app->black); |
---|
419 | d->w3.shadowThickness = |
---|
420 | get_integer_resource("shadowThickness", "ShadowThickness", 3); |
---|
421 | d->w3.borderColor = |
---|
422 | get_pixel_resource("borderColor", "BorderColor", |
---|
423 | app->dpy, app->colormap, app->black); |
---|
424 | d->w3.borderWidth = |
---|
425 | get_integer_resource("borderWidth", "BorderWidth", 1); |
---|
426 | |
---|
427 | d->w3.horizontalSpacing = scaleXDimension(app, |
---|
428 | get_integer_resource("horizontalSpacing", "Spacing", 5)); |
---|
429 | d->w3.verticalSpacing = scaleYDimension(app, |
---|
430 | get_integer_resource("verticalSpacing", "Spacing", 6)); |
---|
431 | |
---|
432 | if (2 == app->argc) { |
---|
433 | labelText = strdup(app->argv[1]); |
---|
434 | } else { |
---|
435 | labelText = |
---|
436 | getStringResourceWithDefault("dialog.label", "Dialog.Label", |
---|
437 | "Please enter your authentication passphrase:"); |
---|
438 | } |
---|
439 | createLabel(app, labelText, &(d->label)); |
---|
440 | freeIf(labelText); |
---|
441 | d->label.font = getFontResource(app, "dialog.font", "Dialog.Font"); |
---|
442 | calcLabelTextExtents(&(d->label)); |
---|
443 | d->label.w.foreground = d->w3.w.foreground; |
---|
444 | d->label.w.background = d->w3.w.background; |
---|
445 | |
---|
446 | d->okButton.w3.w.foreground = |
---|
447 | get_pixel_resource("okButton.foreground", "Button.Foreground", |
---|
448 | app->dpy, app->colormap, app->black); |
---|
449 | d->okButton.w3.w.background = |
---|
450 | get_pixel_resource("okButton.background", "Button.Background", |
---|
451 | app->dpy, app->colormap, app->white); |
---|
452 | d->okButton.w3.topShadowColor = |
---|
453 | get_pixel_resource("okButton.topShadowColor", "Button.TopShadowColor", |
---|
454 | app->dpy, app->colormap, app->white); |
---|
455 | d->okButton.w3.bottomShadowColor = |
---|
456 | get_pixel_resource("okButton.bottomShadowColor", |
---|
457 | "Button.BottomShadowColor", |
---|
458 | app->dpy, app->colormap, app->black); |
---|
459 | d->okButton.w3.shadowThickness = |
---|
460 | get_integer_resource("okButton.shadowThickness", |
---|
461 | "Button.ShadowThickness", 2); |
---|
462 | d->okButton.w3.borderColor = |
---|
463 | get_pixel_resource("okButton.borderColor", "Button.BorderColor", |
---|
464 | app->dpy, app->colormap, app->black); |
---|
465 | d->okButton.w3.borderWidth = |
---|
466 | get_integer_resource("okButton.borderWidth", "Button.BorderWidth", 1); |
---|
467 | d->okButton.w3.horizontalSpacing = scaleXDimension(app, |
---|
468 | get_integer_resource("okButton.horizontalSpacing", "Button.Spacing", 4)); |
---|
469 | d->okButton.w3.verticalSpacing = scaleYDimension(app, |
---|
470 | get_integer_resource("okButton.verticalSpacing", "Button.Spacing", 2)); |
---|
471 | labelText = |
---|
472 | getStringResourceWithDefault("okButton.label", "Button.Label", "OK"); |
---|
473 | createLabel(app, labelText, &(d->okButton.label)); |
---|
474 | freeIf(labelText); |
---|
475 | d->okButton.label.font = |
---|
476 | getFontResource(app, "okButton.font", "Button.Font"); |
---|
477 | calcButtonExtents(&(d->okButton)); |
---|
478 | d->okButton.label.w.foreground = d->okButton.w3.w.foreground; |
---|
479 | d->okButton.label.w.background = d->okButton.w3.w.background; |
---|
480 | |
---|
481 | d->cancelButton.w3.w.foreground = |
---|
482 | get_pixel_resource("cancelButton.foreground", "Button.Foreground", |
---|
483 | app->dpy, app->colormap, app->black); |
---|
484 | d->cancelButton.w3.w.background = |
---|
485 | get_pixel_resource("cancelButton.background", "Button.Background", |
---|
486 | app->dpy, app->colormap, app->white); |
---|
487 | d->cancelButton.w3.topShadowColor = |
---|
488 | get_pixel_resource("cancelButton.topShadowColor", |
---|
489 | "Button.TopShadowColor", |
---|
490 | app->dpy, app->colormap, app->white); |
---|
491 | d->cancelButton.w3.bottomShadowColor = |
---|
492 | get_pixel_resource("cancelButton.bottomShadowColor", |
---|
493 | "Button.BottomShadowColor", |
---|
494 | app->dpy, app->colormap, app->black); |
---|
495 | d->cancelButton.w3.shadowThickness = |
---|
496 | get_integer_resource("cancelButton.shadowThickness", |
---|
497 | "Button.ShadowThickness", 2); |
---|
498 | d->cancelButton.w3.borderColor = |
---|
499 | get_pixel_resource("cancelButton.borderColor", "Button.BorderColor", |
---|
500 | app->dpy, app->colormap, app->black); |
---|
501 | d->cancelButton.w3.borderWidth = |
---|
502 | get_integer_resource("cancelButton.borderWidth", "Button.BorderWidth", |
---|
503 | 1); |
---|
504 | d->cancelButton.w3.horizontalSpacing = scaleXDimension(app, |
---|
505 | get_integer_resource("cancelButton.horizontalSpacing", "Button.Spacing", |
---|
506 | 4)); |
---|
507 | d->cancelButton.w3.verticalSpacing = scaleYDimension(app, |
---|
508 | get_integer_resource("cancelButton.verticalSpacing", "Button.Spacing", |
---|
509 | 2)); |
---|
510 | labelText = |
---|
511 | getStringResourceWithDefault("cancelButton.label", "Button.Label", |
---|
512 | "Cancel"); |
---|
513 | createLabel(app, labelText, &(d->cancelButton.label)); |
---|
514 | freeIf(labelText); |
---|
515 | d->cancelButton.label.font = |
---|
516 | getFontResource(app, "cancelButton.font", "Button.Font"); |
---|
517 | calcButtonExtents(&(d->cancelButton)); |
---|
518 | d->cancelButton.label.w.foreground = d->cancelButton.w3.w.foreground; |
---|
519 | d->cancelButton.label.w.background = d->cancelButton.w3.w.background; |
---|
520 | |
---|
521 | balanceButtonExtents(&(d->okButton), &(d->cancelButton)); |
---|
522 | |
---|
523 | d->indicator.w3.w.foreground = |
---|
524 | get_pixel_resource("indicator.foreground", "Indicator.Foreground", |
---|
525 | app->dpy, app->colormap, app->black); |
---|
526 | d->indicator.w3.w.background = |
---|
527 | get_pixel_resource("indicator.background", "Indicator.Background", |
---|
528 | app->dpy, app->colormap, app->white); |
---|
529 | d->indicator.w3.w.width = scaleXDimension(app, |
---|
530 | get_integer_resource("indicator.width", "Indicator.Width", 15)); |
---|
531 | d->indicator.w3.w.height = scaleYDimension(app, |
---|
532 | get_integer_resource("indicator.height", "Indicator.Height", 7)); |
---|
533 | d->indicator.w3.topShadowColor = |
---|
534 | get_pixel_resource("indicator.topShadowColor", |
---|
535 | "Indicator.TopShadowColor", |
---|
536 | app->dpy, app->colormap, app->white); |
---|
537 | d->indicator.w3.bottomShadowColor = |
---|
538 | get_pixel_resource("indicator.bottomShadowColor", |
---|
539 | "Indicator.BottomShadowColor", |
---|
540 | app->dpy, app->colormap, app->black); |
---|
541 | d->indicator.w3.shadowThickness = |
---|
542 | get_integer_resource("indicator.shadowThickness", |
---|
543 | "Indicator.ShadowThickness", 2); |
---|
544 | d->indicator.w3.borderColor = |
---|
545 | get_pixel_resource("indicator.borderColor", "Indicator.BorderColor", |
---|
546 | app->dpy, app->colormap, app->black); |
---|
547 | d->indicator.w3.borderWidth = |
---|
548 | get_integer_resource("indicator.borderWidth", "Indicator.BorderWidth", |
---|
549 | 0); |
---|
550 | d->indicator.w3.horizontalSpacing = scaleXDimension(app, |
---|
551 | get_integer_resource("indicator.horizontalSpacing", "Indicator.Spacing", |
---|
552 | 2)); |
---|
553 | d->indicator.w3.verticalSpacing =scaleYDimension(app, |
---|
554 | get_integer_resource("indicator.verticalSpacing", "Indicator.Spacing", |
---|
555 | 4)); |
---|
556 | d->indicator.minimumCount = |
---|
557 | get_integer_resource("indicator.minimumCount", "Indicator.MinimumCount", |
---|
558 | 8); |
---|
559 | d->indicator.maximumCount = |
---|
560 | get_integer_resource("indicator.maximumCount", "Indicator.MaximumCount", |
---|
561 | 24); |
---|
562 | d->indicator.w3.interiorWidth = d->indicator.w3.w.width; |
---|
563 | d->indicator.w3.interiorHeight = d->indicator.w3.w.height; |
---|
564 | d->indicator.w3.w.width += (2 * d->indicator.w3.shadowThickness); |
---|
565 | d->indicator.w3.w.width += (2 * d->indicator.w3.borderWidth); |
---|
566 | d->indicator.w3.w.height += (2 * d->indicator.w3.shadowThickness); |
---|
567 | d->indicator.w3.w.height += (2 * d->indicator.w3.borderWidth); |
---|
568 | { |
---|
569 | /* Make sure the indicators can all fit on the screen. |
---|
570 | * 80% of the screen width seems fine. |
---|
571 | */ |
---|
572 | Dimension maxWidth = (WidthOfScreen(app->screen) * 8 / 10); |
---|
573 | Dimension extraSpace = ((2 * d->w3.horizontalSpacing) + |
---|
574 | (2 * d->w3.shadowThickness)); |
---|
575 | |
---|
576 | if (d->indicator.maximumCount < 8) { |
---|
577 | d->indicator.maximumCount = 8; |
---|
578 | } |
---|
579 | if (((d->indicator.maximumCount * d->indicator.w3.w.width) + |
---|
580 | ((d->indicator.maximumCount - 1) * |
---|
581 | d->indicator.w3.horizontalSpacing) + extraSpace) > maxWidth) { |
---|
582 | d->indicator.maximumCount = |
---|
583 | ((maxWidth - extraSpace - d->indicator.w3.w.width) / |
---|
584 | (d->indicator.w3.w.width + d->indicator.w3.horizontalSpacing)) |
---|
585 | + 1; |
---|
586 | } |
---|
587 | if (d->indicator.minimumCount <= 6) { |
---|
588 | d->indicator.minimumCount = 6; |
---|
589 | } |
---|
590 | if (d->indicator.minimumCount > d->indicator.maximumCount) { |
---|
591 | d->indicator.minimumCount = d->indicator.maximumCount; |
---|
592 | } |
---|
593 | } |
---|
594 | |
---|
595 | { |
---|
596 | /* Calculate the width and horizontal position of things. */ |
---|
597 | Dimension labelAreaWidth; |
---|
598 | Dimension buttonAreaWidth; |
---|
599 | Dimension indicatorAreaWidth; |
---|
600 | Dimension extraIndicatorSpace; |
---|
601 | Dimension singleIndicatorSpace; |
---|
602 | Dimension interButtonSpace; |
---|
603 | Dimension w; |
---|
604 | Position leftX; |
---|
605 | int i; |
---|
606 | |
---|
607 | labelAreaWidth = d->label.w.width + (2 * d->w3.horizontalSpacing); |
---|
608 | buttonAreaWidth = ((3 * d->w3.horizontalSpacing) + |
---|
609 | d->okButton.w3.w.width + |
---|
610 | d->cancelButton.w3.w.width); |
---|
611 | w = MAX(labelAreaWidth, buttonAreaWidth); |
---|
612 | extraIndicatorSpace = ((2 * d->w3.horizontalSpacing) + |
---|
613 | d->indicator.w3.w.width); |
---|
614 | singleIndicatorSpace = (d->indicator.w3.w.width + |
---|
615 | d->indicator.w3.horizontalSpacing); |
---|
616 | d->indicator.count = ((w - extraIndicatorSpace) / singleIndicatorSpace); |
---|
617 | d->indicator.current = 0; |
---|
618 | d->indicator.count++; /* For gatepost indicator in extra space. */ |
---|
619 | if (((w - extraIndicatorSpace) % singleIndicatorSpace) > |
---|
620 | (singleIndicatorSpace / 2)) { |
---|
621 | d->indicator.count++; |
---|
622 | } |
---|
623 | if (d->indicator.count < d->indicator.minimumCount) { |
---|
624 | d->indicator.count = d->indicator.minimumCount; |
---|
625 | } |
---|
626 | if (d->indicator.count > d->indicator.maximumCount) { |
---|
627 | d->indicator.count = d->indicator.maximumCount; |
---|
628 | } |
---|
629 | indicatorAreaWidth = ((singleIndicatorSpace * (d->indicator.count - 1)) + |
---|
630 | extraIndicatorSpace); |
---|
631 | d->w3.interiorWidth = MAX(w, indicatorAreaWidth); |
---|
632 | d->w3.w.width = d->w3.interiorWidth + (2 * d->w3.shadowThickness); |
---|
633 | |
---|
634 | leftX = (d->w3.w.width - d->label.w.width) / 2; |
---|
635 | d->label.w.x = leftX; |
---|
636 | |
---|
637 | leftX = ((d->w3.w.width - |
---|
638 | (d->indicator.count * d->indicator.w3.w.width) - |
---|
639 | ((d->indicator.count - 1) * d->indicator.w3.horizontalSpacing)) |
---|
640 | / 2); |
---|
641 | { |
---|
642 | int n = d->indicator.count * sizeof(IndicatorElement); |
---|
643 | d->indicators = malloc(n); |
---|
644 | if (NULL == d->indicators) { |
---|
645 | destroyDialog(app); |
---|
646 | outOfMemory(app, __LINE__); |
---|
647 | } |
---|
648 | memset(d->indicators, 0, n); |
---|
649 | } |
---|
650 | d->indicators[0].parent = &(d->indicator); |
---|
651 | d->indicators[0].w.x = d->indicator.w3.w.x = leftX; |
---|
652 | d->indicators[0].w.width = d->indicator.w3.w.width; |
---|
653 | d->indicators[0].isLit = False; |
---|
654 | for (i = 1; i < d->indicator.count; i++) { |
---|
655 | d->indicators[i].parent = &(d->indicator); |
---|
656 | d->indicators[i].w.x = (d->indicators[i - 1].w.x + |
---|
657 | d->indicator.w3.w.width + |
---|
658 | d->indicator.w3.horizontalSpacing); |
---|
659 | d->indicators[i].w.width = d->indicator.w3.w.width; |
---|
660 | d->indicators[i].isLit = False; |
---|
661 | } |
---|
662 | interButtonSpace = ((d->w3.interiorWidth - d->okButton.w3.w.width - |
---|
663 | d->cancelButton.w3.w.width) / 3); |
---|
664 | d->okButton.w3.w.x = interButtonSpace + d->w3.shadowThickness; |
---|
665 | d->cancelButton.w3.w.x = (d->okButton.w3.w.x + d->okButton.w3.w.width + |
---|
666 | interButtonSpace); |
---|
667 | } |
---|
668 | { |
---|
669 | /* Calculate the height and vertical position of things. */ |
---|
670 | int i; |
---|
671 | |
---|
672 | d->w3.interiorHeight = ((4 * d->w3.verticalSpacing) + |
---|
673 | (2 * d->indicator.w3.verticalSpacing) + |
---|
674 | d->label.w.height + |
---|
675 | d->indicator.w3.w.height + |
---|
676 | d->okButton.w3.w.height); |
---|
677 | d->w3.w.height = d->w3.interiorHeight + (2 * d->w3.shadowThickness); |
---|
678 | d->label.w.y = d->w3.shadowThickness + d->w3.verticalSpacing; |
---|
679 | d->indicator.w3.w.y = (d->label.w.y + d->label.w.height + |
---|
680 | d->w3.verticalSpacing + |
---|
681 | d->indicator.w3.verticalSpacing); |
---|
682 | for (i = 0; i < d->indicator.count; i++) { |
---|
683 | d->indicators[i].w.y = d->indicator.w3.w.y; |
---|
684 | d->indicators[i].w.height = d->indicator.w3.w.height; |
---|
685 | } |
---|
686 | d->okButton.w3.w.y = d->cancelButton.w3.w.y = |
---|
687 | (d->indicator.w3.w.y + d->indicator.w3.w.height + |
---|
688 | d->w3.verticalSpacing + d->indicator.w3.verticalSpacing); |
---|
689 | } |
---|
690 | calcButtonLabelPosition(&(d->okButton)); |
---|
691 | calcButtonLabelPosition(&(d->cancelButton)); |
---|
692 | |
---|
693 | d->w3.w.x = (WidthOfScreen(app->screen) - d->w3.w.width) / 2; |
---|
694 | d->w3.w.y = (HeightOfScreen(app->screen) - d->w3.w.height) / 3; |
---|
695 | |
---|
696 | app->dialog = d; |
---|
697 | } |
---|
698 | |
---|
699 | void destroyLabel(AppInfo *app, LabelInfo *label) |
---|
700 | { |
---|
701 | TextObject *thisTextObject; |
---|
702 | TextObject *nextTextObject; |
---|
703 | |
---|
704 | thisTextObject = label->multiText; |
---|
705 | nextTextObject = thisTextObject->next; |
---|
706 | freeIf(thisTextObject); |
---|
707 | while (NULL != nextTextObject) { |
---|
708 | thisTextObject = nextTextObject; |
---|
709 | nextTextObject = thisTextObject->next; |
---|
710 | freeIf(thisTextObject); |
---|
711 | } |
---|
712 | freeIf(label->fullText); |
---|
713 | freeFontIf(app, label->font); |
---|
714 | } |
---|
715 | |
---|
716 | void destroyDialog(AppInfo *app) |
---|
717 | { |
---|
718 | DialogInfo *d = app->dialog; |
---|
719 | |
---|
720 | freeIf(d->title); |
---|
721 | freeIf(d->indicators); |
---|
722 | |
---|
723 | destroyLabel(app, &(d->label)); |
---|
724 | destroyLabel(app, &(d->okButton.label)); |
---|
725 | destroyLabel(app, &(d->cancelButton.label)); |
---|
726 | |
---|
727 | XFree(d->sizeHints); |
---|
728 | XFree(d->wmHints); |
---|
729 | XFree(d->classHints); |
---|
730 | XFree(d->windowName.value); |
---|
731 | |
---|
732 | freeIf(d); |
---|
733 | } |
---|
734 | |
---|
735 | void createDialogWindow(AppInfo *app) |
---|
736 | { |
---|
737 | XSetWindowAttributes attr; |
---|
738 | unsigned long attrMask = 0; |
---|
739 | DialogInfo *d = app->dialog; |
---|
740 | |
---|
741 | attr.background_pixel = d->w3.w.background; |
---|
742 | attrMask |= CWBackPixel; |
---|
743 | attr.border_pixel = d->w3.borderColor; |
---|
744 | attrMask |= CWBorderPixel; |
---|
745 | attr.cursor = None; |
---|
746 | attrMask |= CWCursor; |
---|
747 | attr.event_mask = app->eventMask; |
---|
748 | attrMask |= CWEventMask; |
---|
749 | |
---|
750 | d->dialogWindow = XCreateWindow(app->dpy, app->rootWindow, |
---|
751 | d->w3.w.x, d->w3.w.y, |
---|
752 | d->w3.w.width, d->w3.w.height, |
---|
753 | d->w3.borderWidth, |
---|
754 | DefaultDepthOfScreen(app->screen), |
---|
755 | InputOutput, |
---|
756 | DefaultVisualOfScreen(app->screen), |
---|
757 | attrMask, &attr); |
---|
758 | |
---|
759 | d->sizeHints = XAllocSizeHints(); |
---|
760 | if (!(d->sizeHints)) { |
---|
761 | destroyDialog(app); |
---|
762 | outOfMemory(app, __LINE__); |
---|
763 | } |
---|
764 | d->sizeHints->flags = 0; |
---|
765 | d->sizeHints->flags |= PPosition; |
---|
766 | d->sizeHints->flags |= PSize; |
---|
767 | d->sizeHints->min_width = d->w3.w.width; |
---|
768 | d->sizeHints->min_height = d->w3.w.height; |
---|
769 | d->sizeHints->flags |= PMinSize; |
---|
770 | d->sizeHints->max_width = d->w3.w.width; |
---|
771 | d->sizeHints->max_height = d->w3.w.height; |
---|
772 | d->sizeHints->flags |= PMaxSize; |
---|
773 | d->sizeHints->base_width = d->w3.w.width; |
---|
774 | d->sizeHints->base_height = d->w3.w.height; |
---|
775 | d->sizeHints->flags |= PBaseSize; |
---|
776 | |
---|
777 | d->wmHints = XAllocWMHints(); |
---|
778 | if (!(d->wmHints)) { |
---|
779 | destroyDialog(app); |
---|
780 | outOfMemory(app, __LINE__); |
---|
781 | } |
---|
782 | d->wmHints->flags = 0; |
---|
783 | d->wmHints->input = True; |
---|
784 | d->wmHints->flags |= InputHint; |
---|
785 | d->wmHints->initial_state = NormalState; |
---|
786 | d->wmHints->flags |= StateHint; |
---|
787 | |
---|
788 | d->classHints = XAllocClassHint(); |
---|
789 | if (!(d->classHints)) { |
---|
790 | destroyDialog(app); |
---|
791 | outOfMemory(app, __LINE__); |
---|
792 | } |
---|
793 | d->classHints->res_name = app->appName; |
---|
794 | d->classHints->res_class = app->appClass; |
---|
795 | |
---|
796 | if (!XStringListToTextProperty(&(d->title), 1, &(d->windowName))) { |
---|
797 | destroyDialog(app); |
---|
798 | outOfMemory(app, __LINE__); |
---|
799 | } |
---|
800 | XSetWMProperties(app->dpy, d->dialogWindow, &(d->windowName), NULL, |
---|
801 | app->argv, app->argc, d->sizeHints, |
---|
802 | d->wmHints, d->classHints); |
---|
803 | XSetTransientForHint(app->dpy, d->dialogWindow, d->dialogWindow); |
---|
804 | |
---|
805 | app->wmDeleteWindowAtom = XInternAtom(app->dpy, "WM_DELETE_WINDOW", False); |
---|
806 | XSetWMProtocols(app->dpy, d->dialogWindow, &(app->wmDeleteWindowAtom), 1); |
---|
807 | } |
---|
808 | |
---|
809 | void createGCs(AppInfo *app) |
---|
810 | { |
---|
811 | DialogInfo *d = app->dialog; |
---|
812 | |
---|
813 | XGCValues gcv; |
---|
814 | unsigned long gcvMask; |
---|
815 | |
---|
816 | gcvMask = 0; |
---|
817 | gcv.foreground = d->w3.w.background; |
---|
818 | gcvMask |= GCForeground; |
---|
819 | gcv.fill_style = FillSolid; |
---|
820 | gcvMask |= GCFillStyle; |
---|
821 | app->fillGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); |
---|
822 | |
---|
823 | gcvMask = 0; |
---|
824 | gcv.foreground = d->w3.borderColor; |
---|
825 | gcvMask |= GCForeground; |
---|
826 | gcv.line_width = d->w3.borderWidth; |
---|
827 | gcvMask |= GCLineWidth; |
---|
828 | gcv.line_style = LineSolid; |
---|
829 | gcvMask |= GCLineStyle; |
---|
830 | gcv.cap_style = CapButt; |
---|
831 | gcvMask |= GCCapStyle; |
---|
832 | gcv.join_style = JoinMiter; |
---|
833 | gcvMask |= GCJoinStyle; |
---|
834 | app->borderGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); |
---|
835 | |
---|
836 | gcvMask = 0; |
---|
837 | gcv.foreground = d->label.w.foreground; |
---|
838 | gcvMask |= GCForeground; |
---|
839 | gcv.background = d->label.w.background; |
---|
840 | gcvMask |= GCBackground; |
---|
841 | gcv.font = d->label.font->fid; |
---|
842 | gcvMask |= GCFont; |
---|
843 | app->textGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); |
---|
844 | |
---|
845 | gcvMask = 0; |
---|
846 | gcv.foreground = d->indicator.w3.w.foreground; |
---|
847 | gcvMask |= GCForeground; |
---|
848 | gcv.fill_style = FillSolid; |
---|
849 | gcvMask |= GCFillStyle; |
---|
850 | app->brightGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); |
---|
851 | |
---|
852 | gcvMask = 0; |
---|
853 | gcv.foreground = d->indicator.w3.w.background; |
---|
854 | gcvMask |= GCForeground; |
---|
855 | gcv.fill_style = FillSolid; |
---|
856 | gcvMask |= GCFillStyle; |
---|
857 | app->dimGC = XCreateGC(app->dpy, app->rootWindow, gcvMask, &gcv); |
---|
858 | } |
---|
859 | |
---|
860 | void destroyGCs(AppInfo *app) |
---|
861 | { |
---|
862 | XFreeGC(app->dpy, app->fillGC); |
---|
863 | XFreeGC(app->dpy, app->borderGC); |
---|
864 | XFreeGC(app->dpy, app->textGC); |
---|
865 | XFreeGC(app->dpy, app->brightGC); |
---|
866 | XFreeGC(app->dpy, app->dimGC); |
---|
867 | } |
---|
868 | |
---|
869 | void paintLabel(AppInfo *app, Drawable draw, LabelInfo label) |
---|
870 | { |
---|
871 | TextObject *t; |
---|
872 | Position x; |
---|
873 | Position y; |
---|
874 | |
---|
875 | if (!(label.fullText)) { |
---|
876 | return; |
---|
877 | } |
---|
878 | XSetForeground(app->dpy, app->textGC, label.w.foreground); |
---|
879 | XSetBackground(app->dpy, app->textGC, label.w.background); |
---|
880 | XSetFont(app->dpy, app->textGC, label.font->fid); |
---|
881 | |
---|
882 | t = label.multiText; |
---|
883 | x = label.w.x; |
---|
884 | y = label.w.y + t->ascent; |
---|
885 | while (NULL != t) { |
---|
886 | if (t->text) { |
---|
887 | XDrawString(app->dpy, draw, app->textGC, x, y, t->text, |
---|
888 | t->textLength); |
---|
889 | } |
---|
890 | y += t->descent; |
---|
891 | t = t->next; |
---|
892 | if (t) { |
---|
893 | y += t->ascent; |
---|
894 | } |
---|
895 | } |
---|
896 | } |
---|
897 | |
---|
898 | void paintButton(AppInfo *app, Drawable draw, ButtonInfo button) |
---|
899 | { |
---|
900 | Position x; |
---|
901 | Position y; |
---|
902 | Dimension width; |
---|
903 | Dimension height; |
---|
904 | |
---|
905 | if (button.w3.borderWidth > 0) { |
---|
906 | XSetForeground(app->dpy, app->borderGC, button.w3.borderColor); |
---|
907 | XFillRectangle(app->dpy, draw, app->borderGC, button.w3.w.x, |
---|
908 | button.w3.w.y, button.w3.w.width, button.w3.w.height); |
---|
909 | } |
---|
910 | if ((button.w3.shadowThickness <= 0) && (button.pressed)) { |
---|
911 | Pixel tmp = button.w3.w.background; |
---|
912 | button.w3.w.background = button.w3.w.foreground; |
---|
913 | button.w3.w.foreground = tmp; |
---|
914 | tmp = button.label.w.background; |
---|
915 | button.label.w.background = button.label.w.foreground; |
---|
916 | button.label.w.foreground = tmp; |
---|
917 | } |
---|
918 | x = (button.w3.w.x + button.w3.borderWidth); |
---|
919 | y = (button.w3.w.y + button.w3.borderWidth); |
---|
920 | width = (button.w3.w.width - (2 * button.w3.borderWidth)); |
---|
921 | height = (button.w3.w.height - (2 * button.w3.borderWidth)); |
---|
922 | if ((button.w3.shadowThickness > 0) && (button.pressed)) { |
---|
923 | XSetForeground(app->dpy, app->fillGC, button.w3.topShadowColor); |
---|
924 | } else { |
---|
925 | XSetForeground(app->dpy, app->fillGC, button.w3.w.background); |
---|
926 | } |
---|
927 | XFillRectangle(app->dpy, draw, app->fillGC, x, y, width, height); |
---|
928 | if (button.w3.shadowThickness > 0) { |
---|
929 | if (button.pressed) { |
---|
930 | draw_shaded_rectangle(app->dpy, draw, x, y, width, height, |
---|
931 | button.w3.shadowThickness, |
---|
932 | button.w3.bottomShadowColor, |
---|
933 | button.w3.topShadowColor); |
---|
934 | } else { |
---|
935 | draw_shaded_rectangle(app->dpy, draw, x, y, width, height, |
---|
936 | button.w3.shadowThickness, |
---|
937 | button.w3.topShadowColor, |
---|
938 | button.w3.bottomShadowColor); |
---|
939 | } |
---|
940 | } |
---|
941 | if ((button.w3.shadowThickness > 0) && (button.pressed)) { |
---|
942 | Dimension pressedAdjustment; |
---|
943 | |
---|
944 | pressedAdjustment = button.w3.shadowThickness / 2; |
---|
945 | if (pressedAdjustment < 1) { |
---|
946 | pressedAdjustment = 1; |
---|
947 | } |
---|
948 | x = button.label.w.x; |
---|
949 | y = button.label.w.y; |
---|
950 | button.label.w.x += pressedAdjustment; |
---|
951 | button.label.w.y += pressedAdjustment; |
---|
952 | paintLabel(app, draw, button.label); |
---|
953 | button.label.w.x = x; |
---|
954 | button.label.w.y = y; |
---|
955 | } else { |
---|
956 | paintLabel(app, draw, button.label); |
---|
957 | } |
---|
958 | if ((button.w3.shadowThickness <= 0) && (button.pressed)) { |
---|
959 | Pixel tmp = button.w3.w.background; |
---|
960 | button.w3.w.background = button.w3.w.foreground; |
---|
961 | button.w3.w.foreground = tmp; |
---|
962 | tmp = button.label.w.background; |
---|
963 | button.label.w.background = button.label.w.foreground; |
---|
964 | button.label.w.foreground = tmp; |
---|
965 | } |
---|
966 | } |
---|
967 | |
---|
968 | void paintIndicator(AppInfo *app, Drawable draw, IndicatorElement indicator) |
---|
969 | { |
---|
970 | Position x; |
---|
971 | Position y; |
---|
972 | Dimension width; |
---|
973 | Dimension height; |
---|
974 | GC gc = app->dimGC; |
---|
975 | |
---|
976 | if (indicator.parent->w3.borderWidth > 0) { |
---|
977 | XSetForeground(app->dpy, app->borderGC, |
---|
978 | indicator.parent->w3.borderColor); |
---|
979 | XFillRectangle(app->dpy, draw, app->borderGC, indicator.w.x, |
---|
980 | indicator.w.y, indicator.w.width, indicator.w.height); |
---|
981 | } |
---|
982 | if (indicator.isLit) { |
---|
983 | gc = app->brightGC; |
---|
984 | } |
---|
985 | x = (indicator.w.x + indicator.parent->w3.borderWidth); |
---|
986 | y = (indicator.w.y + indicator.parent->w3.borderWidth); |
---|
987 | width = (indicator.w.width - (2 * indicator.parent->w3.borderWidth)); |
---|
988 | height = (indicator.w.height - (2 * indicator.parent->w3.borderWidth)); |
---|
989 | XFillRectangle(app->dpy, draw, gc, x, y, width, height); |
---|
990 | if (indicator.parent->w3.shadowThickness > 0) { |
---|
991 | draw_shaded_rectangle(app->dpy, draw, x, y, width, height, |
---|
992 | indicator.parent->w3.shadowThickness, |
---|
993 | indicator.parent->w3.bottomShadowColor, |
---|
994 | indicator.parent->w3.topShadowColor); |
---|
995 | } |
---|
996 | } |
---|
997 | |
---|
998 | void updateIndicatorElement(AppInfo *app, int i) |
---|
999 | { |
---|
1000 | DialogInfo *d = app->dialog; |
---|
1001 | |
---|
1002 | d->indicators[i].isLit = !(d->indicators[i].isLit); |
---|
1003 | paintIndicator(app, d->dialogWindow, d->indicators[i]); |
---|
1004 | } |
---|
1005 | |
---|
1006 | void updateIndicators(AppInfo *app, int condition) |
---|
1007 | { |
---|
1008 | DialogInfo *d = app->dialog; |
---|
1009 | |
---|
1010 | if (condition > 0) { |
---|
1011 | /* Move forward one. */ |
---|
1012 | updateIndicatorElement(app, d->indicator.current); |
---|
1013 | if (d->indicator.current < (d->indicator.count - 1)) { |
---|
1014 | (d->indicator.current)++; |
---|
1015 | } else { |
---|
1016 | d->indicator.current = 0; |
---|
1017 | } |
---|
1018 | } else if (condition < 0) { |
---|
1019 | /* Move backward one. */ |
---|
1020 | if (d->indicator.current > 0) { |
---|
1021 | (d->indicator.current)--; |
---|
1022 | } else { |
---|
1023 | d->indicator.current = d->indicator.count - 1; |
---|
1024 | } |
---|
1025 | updateIndicatorElement(app, d->indicator.current); |
---|
1026 | } else { |
---|
1027 | /* Erase them all. */ |
---|
1028 | int i; |
---|
1029 | |
---|
1030 | for (i = 0; i < d->indicator.count; i++) { |
---|
1031 | d->indicators[i].isLit = False; |
---|
1032 | paintIndicator(app, d->dialogWindow, d->indicators[i]); |
---|
1033 | } |
---|
1034 | d->indicator.current = 0; |
---|
1035 | } |
---|
1036 | XSync(app->dpy, False); |
---|
1037 | } |
---|
1038 | |
---|
1039 | void paintDialog(AppInfo *app) |
---|
1040 | { |
---|
1041 | DialogInfo *d = app->dialog; |
---|
1042 | Drawable draw = d->dialogWindow; |
---|
1043 | int i; |
---|
1044 | |
---|
1045 | XSetForeground(app->dpy, app->fillGC, d->w3.w.background); |
---|
1046 | XFillRectangle(app->dpy, draw, app->fillGC, 0, 0, |
---|
1047 | d->w3.w.width, d->w3.w.height); |
---|
1048 | if (d->w3.shadowThickness > 0) { |
---|
1049 | draw_shaded_rectangle(app->dpy, draw, 0, 0, |
---|
1050 | d->w3.w.width, d->w3.w.height, |
---|
1051 | d->w3.shadowThickness, |
---|
1052 | d->w3.topShadowColor, |
---|
1053 | d->w3.bottomShadowColor); |
---|
1054 | } |
---|
1055 | paintLabel(app, draw, d->label); |
---|
1056 | for (i = 0; i < d->indicator.count; i++) { |
---|
1057 | paintIndicator(app, draw, d->indicators[i]); |
---|
1058 | } |
---|
1059 | paintButton(app, draw, d->okButton); |
---|
1060 | paintButton(app, draw, d->cancelButton); |
---|
1061 | XSync(app->dpy, False); |
---|
1062 | } |
---|
1063 | |
---|
1064 | void performGrab(AppInfo *app, int grabType, char *grabTypeName, |
---|
1065 | Bool shouldGrab, Bool *isGrabbed) { |
---|
1066 | if ((!(shouldGrab)) || (*isGrabbed)) { |
---|
1067 | return; |
---|
1068 | } else if ((GRAB_KEYBOARD != grabType) && (GRAB_POINTER != grabType)) { |
---|
1069 | fprintf(stderr, "%s[%ld]: performGrab: invalid grab type (%d).\n", |
---|
1070 | app->appName, (long) app->pid, grabType); |
---|
1071 | return; |
---|
1072 | } else { |
---|
1073 | int status = GrabInvalidTime; /* keep gcc -Wall from complaining */ |
---|
1074 | unsigned int seconds = 0; |
---|
1075 | int helpful_message = 0; |
---|
1076 | /* keyboard and pointer */ |
---|
1077 | Window grabWindow = app->dialog->dialogWindow; |
---|
1078 | Bool ownerEvents = False; |
---|
1079 | Bool pointerMode = GrabModeAsync; |
---|
1080 | Bool keyboardMode = GrabModeAsync; |
---|
1081 | /* pointer only */ |
---|
1082 | unsigned int eventMask = ButtonPressMask | ButtonReleaseMask; |
---|
1083 | Window confineTo = None; |
---|
1084 | Cursor cursor = None; |
---|
1085 | |
---|
1086 | *isGrabbed = True; |
---|
1087 | |
---|
1088 | if (NULL == grabTypeName) { |
---|
1089 | fprintf(stderr, "%s[%ld]: performGrab: null grab type name.\n", |
---|
1090 | app->appName, (long) app->pid); |
---|
1091 | } |
---|
1092 | |
---|
1093 | if (0 == app->grabFailTimeout) { |
---|
1094 | /* Ensure we try to perform the grab at least once. */ |
---|
1095 | app->grabFailTimeout = 1; |
---|
1096 | } |
---|
1097 | while (seconds < app->grabFailTimeout) { |
---|
1098 | XSync(app->dpy, False); |
---|
1099 | switch (grabType) { |
---|
1100 | case GRAB_KEYBOARD: |
---|
1101 | status = XGrabKeyboard(app->dpy, grabWindow, ownerEvents, |
---|
1102 | pointerMode, keyboardMode, CurrentTime); |
---|
1103 | break; |
---|
1104 | case GRAB_POINTER: |
---|
1105 | status = XGrabPointer(app->dpy, grabWindow, ownerEvents, |
---|
1106 | eventMask, pointerMode, keyboardMode, |
---|
1107 | confineTo, cursor, CurrentTime); |
---|
1108 | break; |
---|
1109 | } |
---|
1110 | XSync(app->dpy, False); |
---|
1111 | if (GrabSuccess == status) { |
---|
1112 | if (helpful_message) { |
---|
1113 | fprintf(stderr, "%s[%ld]: Got %s.\n", |
---|
1114 | app->appName, (long) app->pid, grabTypeName); |
---|
1115 | } |
---|
1116 | break; |
---|
1117 | } |
---|
1118 | if (!helpful_message) { |
---|
1119 | fprintf(stderr, "%s[%ld]: Trying to grab %s ...\n", |
---|
1120 | app->appName, (long) app->pid, grabTypeName); |
---|
1121 | helpful_message = 1; |
---|
1122 | } |
---|
1123 | seconds += app->grabRetryInterval; |
---|
1124 | sleep(app->grabRetryInterval); |
---|
1125 | } |
---|
1126 | if (GrabSuccess != status) { |
---|
1127 | char *reason = "reason unknown"; |
---|
1128 | |
---|
1129 | switch (status) { |
---|
1130 | case AlreadyGrabbed: |
---|
1131 | reason = "someone else already has it"; |
---|
1132 | break; |
---|
1133 | case GrabFrozen: |
---|
1134 | reason = "someone else has frozen it"; |
---|
1135 | break; |
---|
1136 | case GrabInvalidTime: |
---|
1137 | reason = "bad grab time [this shouldn't happen]"; |
---|
1138 | break; |
---|
1139 | case GrabNotViewable: |
---|
1140 | reason = "grab not viewable [this shouldn't happen]"; |
---|
1141 | break; |
---|
1142 | } |
---|
1143 | fprintf(stderr, "%s[%ld]: Could not grab %s (%s)\n", |
---|
1144 | app->appName, (long) app->pid, grabTypeName, reason); |
---|
1145 | exitApp(app, EXIT_STATUS_ERROR); |
---|
1146 | } |
---|
1147 | } |
---|
1148 | } |
---|
1149 | |
---|
1150 | |
---|
1151 | void grabKeyboard(AppInfo *app) |
---|
1152 | { |
---|
1153 | performGrab(app, GRAB_KEYBOARD, "keyboard", app->grabKeyboard, |
---|
1154 | &(app->isKeyboardGrabbed)); |
---|
1155 | } |
---|
1156 | |
---|
1157 | void ungrabKeyboard(AppInfo *app) |
---|
1158 | { |
---|
1159 | if (app->grabKeyboard) { |
---|
1160 | XUngrabKeyboard(app->dpy, CurrentTime); |
---|
1161 | } |
---|
1162 | } |
---|
1163 | |
---|
1164 | void grabPointer(AppInfo *app) |
---|
1165 | { |
---|
1166 | performGrab(app, GRAB_POINTER, "pointer", app->grabPointer, |
---|
1167 | &(app->isPointerGrabbed)); |
---|
1168 | } |
---|
1169 | |
---|
1170 | void ungrabPointer(AppInfo *app) |
---|
1171 | { |
---|
1172 | if (app->grabPointer) { |
---|
1173 | XUngrabPointer(app->dpy, CurrentTime); |
---|
1174 | } |
---|
1175 | } |
---|
1176 | |
---|
1177 | void grabServer(AppInfo *app) |
---|
1178 | { |
---|
1179 | if ((!(app->grabServer)) || (app->isServerGrabbed)) { |
---|
1180 | return; |
---|
1181 | } else { |
---|
1182 | app->isServerGrabbed = True; |
---|
1183 | XSync(app->dpy, False); |
---|
1184 | XGrabServer(app->dpy); |
---|
1185 | XSync(app->dpy, False); |
---|
1186 | } |
---|
1187 | } |
---|
1188 | |
---|
1189 | void ungrabServer(AppInfo *app) |
---|
1190 | { |
---|
1191 | if (app->grabServer) { |
---|
1192 | XUngrabServer(app->dpy); |
---|
1193 | } |
---|
1194 | } |
---|
1195 | |
---|
1196 | void cleanUp(AppInfo *app) |
---|
1197 | { |
---|
1198 | cancelInputTimeout(app); |
---|
1199 | XDestroyWindow(app->dpy, app->dialog->dialogWindow); |
---|
1200 | destroyGCs(app); |
---|
1201 | destroyDialog(app); |
---|
1202 | if (app->buf) { |
---|
1203 | memset(app->buf, 0, app->bufSize); |
---|
1204 | } |
---|
1205 | freeIf(app->buf); |
---|
1206 | ungrabPointer(app); |
---|
1207 | ungrabKeyboard(app); |
---|
1208 | ungrabServer(app); |
---|
1209 | } |
---|
1210 | |
---|
1211 | void exitApp(AppInfo *app, int exitCode) |
---|
1212 | { |
---|
1213 | cleanUp(app); |
---|
1214 | exit(exitCode); |
---|
1215 | } |
---|
1216 | |
---|
1217 | void acceptAction(AppInfo *app) |
---|
1218 | { |
---|
1219 | int status = append_to_buf(&(app->buf), &(app->bufSize), |
---|
1220 | &(app->bufIndex), '\0'); |
---|
1221 | if (APPEND_FAILURE == status) { |
---|
1222 | cleanUp(app); |
---|
1223 | outOfMemory(app, __LINE__); |
---|
1224 | } |
---|
1225 | fputs(app->buf, stdout); |
---|
1226 | fputc('\n', stdout); |
---|
1227 | exitApp(app, EXIT_STATUS_ACCEPT); |
---|
1228 | } |
---|
1229 | |
---|
1230 | void cancelAction(AppInfo *app) |
---|
1231 | { |
---|
1232 | exitApp(app, EXIT_STATUS_CANCEL); |
---|
1233 | } |
---|
1234 | |
---|
1235 | void backspacePassphrase(AppInfo *app) |
---|
1236 | { |
---|
1237 | if (0 >= app->bufIndex) { |
---|
1238 | XBell(app->dpy, 0); |
---|
1239 | return; |
---|
1240 | } |
---|
1241 | (app->bufIndex)--; |
---|
1242 | updateIndicators(app, -1); |
---|
1243 | } |
---|
1244 | |
---|
1245 | void erasePassphrase(AppInfo *app) |
---|
1246 | { |
---|
1247 | if (0 >= app->bufIndex) { |
---|
1248 | XBell(app->dpy, 0); |
---|
1249 | return; |
---|
1250 | } |
---|
1251 | updateIndicators(app, 0); |
---|
1252 | app->bufIndex = 0; |
---|
1253 | } |
---|
1254 | |
---|
1255 | void addToPassphrase(AppInfo *app, char c) |
---|
1256 | { |
---|
1257 | int status = append_to_buf(&(app->buf), &(app->bufSize), |
---|
1258 | &(app->bufIndex), c); |
---|
1259 | if (APPEND_FAILURE == status) { |
---|
1260 | cleanUp(app); |
---|
1261 | outOfMemory(app, __LINE__); |
---|
1262 | } |
---|
1263 | updateIndicators(app, 1); |
---|
1264 | } |
---|
1265 | |
---|
1266 | void handleKeyPress(AppInfo *app, XEvent *event) |
---|
1267 | { |
---|
1268 | char s[2]; |
---|
1269 | int n; |
---|
1270 | |
---|
1271 | if (event->xkey.send_event) { |
---|
1272 | /* Pay no attention to synthetic key events. */ |
---|
1273 | return; |
---|
1274 | } |
---|
1275 | cancelInputTimeout(app); |
---|
1276 | n = XLookupString(&(event->xkey), s, 1, NULL, NULL); |
---|
1277 | |
---|
1278 | if (1 != n) { |
---|
1279 | return; |
---|
1280 | } |
---|
1281 | s[1] = '\0'; |
---|
1282 | switch (s[0]) { |
---|
1283 | case '\010': |
---|
1284 | case '\177': |
---|
1285 | backspacePassphrase(app); |
---|
1286 | break; |
---|
1287 | case '\025': |
---|
1288 | case '\030': |
---|
1289 | erasePassphrase(app); |
---|
1290 | break; |
---|
1291 | case '\012': |
---|
1292 | case '\015': |
---|
1293 | acceptAction(app); |
---|
1294 | break; |
---|
1295 | case '\033': |
---|
1296 | cancelAction(app); |
---|
1297 | break; |
---|
1298 | default: |
---|
1299 | addToPassphrase(app, s[0]); |
---|
1300 | break; |
---|
1301 | } |
---|
1302 | } |
---|
1303 | |
---|
1304 | Bool eventIsInsideButton(AppInfo *app, XEvent *event, ButtonInfo button) |
---|
1305 | { |
---|
1306 | /* 'gcc -Wall' complains about 'app' being an unused parameter. |
---|
1307 | * Tough. We might want to use it later, and then we don't have |
---|
1308 | * to change it in each place it's called. Performance won't suffer. |
---|
1309 | */ |
---|
1310 | int status = False; |
---|
1311 | int x, y; |
---|
1312 | |
---|
1313 | switch(event->type) { |
---|
1314 | case ButtonPress: |
---|
1315 | case ButtonRelease: |
---|
1316 | x = event->xbutton.x; |
---|
1317 | y = event->xbutton.y; |
---|
1318 | break; |
---|
1319 | case MotionNotify: |
---|
1320 | x = event->xmotion.x; |
---|
1321 | y = event->xmotion.y; |
---|
1322 | break; |
---|
1323 | default: |
---|
1324 | return(False); |
---|
1325 | } |
---|
1326 | if ((x >= (button.w3.w.x + button.w3.borderWidth)) && |
---|
1327 | (x < (button.w3.w.x + button.w3.w.width - |
---|
1328 | (2 * button.w3.borderWidth))) && |
---|
1329 | (y >= (button.w3.w.y + button.w3.borderWidth)) && |
---|
1330 | (y < (button.w3.w.y + button.w3.w.height - |
---|
1331 | (2 * button.w3.borderWidth)))) { |
---|
1332 | status = True; |
---|
1333 | } |
---|
1334 | return(status); |
---|
1335 | } |
---|
1336 | |
---|
1337 | void handleButtonPress(AppInfo *app, XEvent *event) |
---|
1338 | { |
---|
1339 | DialogInfo *d = app->dialog; |
---|
1340 | |
---|
1341 | cancelInputTimeout(app); |
---|
1342 | if (event->xbutton.button != Button1) { |
---|
1343 | return; |
---|
1344 | } |
---|
1345 | if (ButtonPress == event->type) { |
---|
1346 | if (eventIsInsideButton(app, event, d->okButton)) { |
---|
1347 | d->pressedButton = OK_BUTTON; |
---|
1348 | d->okButton.pressed = True; |
---|
1349 | paintButton(app, d->dialogWindow, d->okButton); |
---|
1350 | } else if (eventIsInsideButton(app, event, d->cancelButton)) { |
---|
1351 | d->pressedButton = CANCEL_BUTTON; |
---|
1352 | d->cancelButton.pressed = True; |
---|
1353 | paintButton(app, d->dialogWindow, d->cancelButton); |
---|
1354 | } else { |
---|
1355 | d->pressedButton = NO_BUTTON; |
---|
1356 | } |
---|
1357 | } else if (ButtonRelease == event->type) { |
---|
1358 | if (OK_BUTTON == d->pressedButton) { |
---|
1359 | if (eventIsInsideButton(app, event, d->okButton)) { |
---|
1360 | acceptAction(app); |
---|
1361 | } else { |
---|
1362 | if (d->okButton.pressed) { |
---|
1363 | d->okButton.pressed = False; |
---|
1364 | paintButton(app, d->dialogWindow, d->okButton); |
---|
1365 | } |
---|
1366 | } |
---|
1367 | } else if (CANCEL_BUTTON == d->pressedButton) { |
---|
1368 | if (eventIsInsideButton(app, event, d->cancelButton)) { |
---|
1369 | cancelAction(app); |
---|
1370 | } else { |
---|
1371 | if (d->cancelButton.pressed) { |
---|
1372 | d->cancelButton.pressed = False; |
---|
1373 | paintButton(app, d->dialogWindow, d->cancelButton); |
---|
1374 | } |
---|
1375 | } |
---|
1376 | } |
---|
1377 | d->pressedButton = NO_BUTTON; |
---|
1378 | } |
---|
1379 | } |
---|
1380 | |
---|
1381 | void handlePointerMotion(AppInfo *app, XEvent *event) |
---|
1382 | { |
---|
1383 | DialogInfo *d = app->dialog; |
---|
1384 | |
---|
1385 | if (NO_BUTTON == d->pressedButton) { |
---|
1386 | return; |
---|
1387 | } else if (OK_BUTTON == d->pressedButton) { |
---|
1388 | if (eventIsInsideButton(app, event, d->okButton)) { |
---|
1389 | if (!(d->okButton.pressed)) { |
---|
1390 | d->okButton.pressed = True; |
---|
1391 | paintButton(app, d->dialogWindow, d->okButton); |
---|
1392 | } |
---|
1393 | } else { |
---|
1394 | if (d->okButton.pressed) { |
---|
1395 | d->okButton.pressed = False; |
---|
1396 | paintButton(app, d->dialogWindow, d->okButton); |
---|
1397 | } |
---|
1398 | } |
---|
1399 | } else if (CANCEL_BUTTON == d->pressedButton) { |
---|
1400 | if (eventIsInsideButton(app, event, d->cancelButton)) { |
---|
1401 | if (!(d->cancelButton.pressed)) { |
---|
1402 | d->cancelButton.pressed = True; |
---|
1403 | paintButton(app, d->dialogWindow, d->cancelButton); |
---|
1404 | } |
---|
1405 | } else { |
---|
1406 | if (d->cancelButton.pressed) { |
---|
1407 | d->cancelButton.pressed = False; |
---|
1408 | paintButton(app, d->dialogWindow, d->cancelButton); |
---|
1409 | } |
---|
1410 | } |
---|
1411 | } |
---|
1412 | } |
---|
1413 | |
---|
1414 | void handleInputTimeout(XtPointer data, XtIntervalId *timerId) |
---|
1415 | { |
---|
1416 | /* 'gcc -Wall' complains about 'timerId' being an unused parameter. |
---|
1417 | * Tough. Xt forces us to have it here. Like it. |
---|
1418 | */ |
---|
1419 | AppInfo *app = (AppInfo *) data; |
---|
1420 | if (app->inputTimeoutActive) { |
---|
1421 | app->inputTimeoutActive = False; |
---|
1422 | fprintf(stderr, "%s[%ld]: *Yawn*...timed out after %lu seconds.\n", |
---|
1423 | app->appName, (long) app->pid, (app->inputTimeout / 1000)); |
---|
1424 | exitApp(app, EXIT_STATUS_TIMEOUT); |
---|
1425 | } |
---|
1426 | } |
---|
1427 | |
---|
1428 | void cancelInputTimeout(AppInfo *app) |
---|
1429 | { |
---|
1430 | if (app->inputTimeoutActive) { |
---|
1431 | app->inputTimeoutActive = False; |
---|
1432 | XtRemoveTimeOut(app->inputTimeoutTimerId); |
---|
1433 | } |
---|
1434 | } |
---|
1435 | |
---|
1436 | int main(int argc, char **argv) |
---|
1437 | { |
---|
1438 | AppInfo app; |
---|
1439 | XEvent event; |
---|
1440 | |
---|
1441 | memset(&app, 0, sizeof(app)); |
---|
1442 | |
---|
1443 | progclass = "SshAskpass"; |
---|
1444 | app.toplevelShell = XtAppInitialize(&(app.appContext), progclass, |
---|
1445 | NULL, 0, &argc, argv, |
---|
1446 | defaults, NULL, 0); |
---|
1447 | app.argc = argc; |
---|
1448 | app.argv = argv; |
---|
1449 | app.dpy = XtDisplay(app.toplevelShell); |
---|
1450 | app.screen = DefaultScreenOfDisplay(app.dpy); |
---|
1451 | app.rootWindow = RootWindowOfScreen(app.screen); |
---|
1452 | app.black = BlackPixel(app.dpy, DefaultScreen(app.dpy)); |
---|
1453 | app.white = WhitePixel(app.dpy, DefaultScreen(app.dpy)); |
---|
1454 | app.colormap = DefaultColormapOfScreen(app.screen); |
---|
1455 | app.resourceDb = XtDatabase(app.dpy); |
---|
1456 | XtGetApplicationNameAndClass(app.dpy, &progname, &progclass); |
---|
1457 | app.appName = progname; |
---|
1458 | app.appClass = progclass; |
---|
1459 | /* For resources.c. */ |
---|
1460 | db = app.resourceDb; |
---|
1461 | |
---|
1462 | /* Seconds after which keyboard/pointer grab fail. */ |
---|
1463 | app.grabFailTimeout = 5; |
---|
1464 | /* Number of seconds to wait between grab attempts. */ |
---|
1465 | app.grabRetryInterval = 1; |
---|
1466 | |
---|
1467 | app.pid = getpid(); |
---|
1468 | |
---|
1469 | { |
---|
1470 | struct rlimit resourceLimit; |
---|
1471 | int status; |
---|
1472 | |
---|
1473 | status = getrlimit(RLIMIT_CORE, &resourceLimit); |
---|
1474 | if (-1 == status) { |
---|
1475 | fprintf(stderr, "%s[%ld]: getrlimit failed (%s)\n", app.appName, |
---|
1476 | (long) app.pid, strerror(errno)); |
---|
1477 | exit(EXIT_STATUS_ERROR); |
---|
1478 | } |
---|
1479 | resourceLimit.rlim_cur = 0; |
---|
1480 | status = setrlimit(RLIMIT_CORE, &resourceLimit); |
---|
1481 | if (-1 == status) { |
---|
1482 | fprintf(stderr, "%s[%ld]: setrlimit failed (%s)\n", app.appName, |
---|
1483 | (long) app.pid, strerror(errno)); |
---|
1484 | exit(EXIT_STATUS_ERROR); |
---|
1485 | } |
---|
1486 | } |
---|
1487 | |
---|
1488 | app.xResolution = |
---|
1489 | WidthOfScreen(app.screen) * 1000 / WidthMMOfScreen(app.screen); |
---|
1490 | app.yResolution = |
---|
1491 | HeightOfScreen(app.screen) * 1000 / HeightMMOfScreen(app.screen); |
---|
1492 | |
---|
1493 | createDialog(&app); |
---|
1494 | createGCs(&app); |
---|
1495 | |
---|
1496 | app.eventMask = 0; |
---|
1497 | app.eventMask |= ExposureMask; |
---|
1498 | app.eventMask |= ButtonPressMask; |
---|
1499 | app.eventMask |= ButtonReleaseMask; |
---|
1500 | app.eventMask |= Button1MotionMask; |
---|
1501 | app.eventMask |= KeyPressMask; |
---|
1502 | |
---|
1503 | createDialogWindow(&app); |
---|
1504 | |
---|
1505 | XMapWindow(app.dpy, app.dialog->dialogWindow); |
---|
1506 | if (app.inputTimeout > 0) { |
---|
1507 | app.inputTimeoutActive = True; |
---|
1508 | app.inputTimeoutTimerId = |
---|
1509 | XtAppAddTimeOut(app.appContext, app.inputTimeout, |
---|
1510 | handleInputTimeout, (XtPointer) &app); |
---|
1511 | } |
---|
1512 | |
---|
1513 | |
---|
1514 | while(True) { |
---|
1515 | XtAppNextEvent(app.appContext, &event); |
---|
1516 | switch (event.type) { |
---|
1517 | case Expose: |
---|
1518 | grabServer(&app); |
---|
1519 | grabKeyboard(&app); |
---|
1520 | grabPointer(&app); |
---|
1521 | if (event.xexpose.count) { |
---|
1522 | break; |
---|
1523 | } |
---|
1524 | paintDialog(&app); |
---|
1525 | break; |
---|
1526 | case ButtonPress: |
---|
1527 | case ButtonRelease: |
---|
1528 | handleButtonPress(&app, &event); |
---|
1529 | break; |
---|
1530 | case MotionNotify: |
---|
1531 | handlePointerMotion(&app, &event); |
---|
1532 | case KeyPress: |
---|
1533 | handleKeyPress(&app, &event); |
---|
1534 | break; |
---|
1535 | case ClientMessage: |
---|
1536 | if ((32 == event.xclient.format) && |
---|
1537 | ((unsigned long) event.xclient.data.l[0] == |
---|
1538 | app.wmDeleteWindowAtom)) { |
---|
1539 | cancelAction(&app); |
---|
1540 | } |
---|
1541 | break; |
---|
1542 | default: |
---|
1543 | break; |
---|
1544 | } |
---|
1545 | } |
---|
1546 | |
---|
1547 | fprintf(stderr, "%s[%ld]: This should not happen.\n", app.appName, |
---|
1548 | (long) app.pid); |
---|
1549 | return(EXIT_STATUS_ANOMALY); |
---|
1550 | } |
---|
1551 | |
---|