1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2004-2021 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "config.h"
25 
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <X11/Xlib.h>
32 #include <X11/keysym.h>
33 #include "alert.h"
34 #include "lang.h"
35 #include "session.h"
36 #include "util.h"
37 #if USE_COMPOSITE
38 #include <X11/extensions/Xcomposite.h>
39 #endif
40 
41 #define ExTextExtents XmbTextExtents
42 #define ExDrawString XmbDrawString
43 
44 #define ExSetColor(pxc, r, g, b) \
45   do { \
46     (pxc)->red = (r << 8) | r; (pxc)->green = (g << 8) | g; (pxc)->blue = (b << 8) | b; \
47   } while (0)
48 
49 static XFontSet     xfs = NULL;
50 
51 #define DRAW_BOX_OUT(mdd, mgc, mwin, mx, my, mw, mh) \
52         AlertDrawBox(mdd, mgc, mwin, mx, my, mw, mh, \
53         colorful, cols[0], cols[2], cols[3])
54 #define DRAW_BOX_IN(mdd, mgc, mwin, mx, my, mw, mh) \
55         AlertDrawBox(mdd, mgc, mwin, mx, my, mw, mh, \
56         colorful, cols[2], cols[0], cols[3])
57 static void
AlertDrawBox(Display * mdd,GC mgc,Window mwin,int mx,int my,int mw,int mh,int colorful,unsigned int c1,unsigned int c2,unsigned int cb)58 AlertDrawBox(Display * mdd, GC mgc, Window mwin, int mx, int my, int mw, int mh,
59 	     int colorful, unsigned int c1, unsigned int c2, unsigned int cb)
60 {
61    if (colorful)
62      {
63 	XSetForeground(mdd, mgc, cb);
64 	XDrawRectangle(mdd, mwin, mgc, mx, my, mw - 1, mh - 1);
65 	XSetForeground(mdd, mgc, c1);
66 	XDrawLine(mdd, mwin, mgc, mx + 1, my + 1, mx + mw - 3, my + 1);
67 	XDrawLine(mdd, mwin, mgc, mx + 1, my + 1, mx + 1, my + mh - 3);
68 	XSetForeground(mdd, mgc, c2);
69 	XDrawLine(mdd, mwin, mgc, mx + 2, my + mh - 2, mx + mw - 2,
70 		  my + mh - 2);
71 	XDrawLine(mdd, mwin, mgc, mx + mw - 2, my + 2, mx + mw - 2,
72 		  my + mh - 2);
73      }
74    else
75      {
76 	XDrawRectangle(mdd, mwin, mgc, mx, my, mw - 1, mh - 1);
77      }
78 }
79 
80 #define DRAW_THIN_BOX_IN(mdd, mgc, mwin, mx, my, mw, mh) \
81         AlertDrawThinBoxIn(mdd, mgc, mwin, mx, my, mw, mh, \
82         colorful, cols[2], cols[0])
83 static void
AlertDrawThinBoxIn(Display * mdd,GC mgc,Window mwin,int mx,int my,int mw,int mh,int colorful,unsigned int c1,unsigned int c2)84 AlertDrawThinBoxIn(Display * mdd, GC mgc, Window mwin, int mx, int my, int mw,
85 		   int mh, int colorful, unsigned int c1, unsigned int c2)
86 {
87    if (colorful)
88      {
89 	XSetForeground(mdd, mgc, c1);
90 	XDrawLine(mdd, mwin, mgc, mx + 1, my + 1, mx + mw - 3, my + 1);
91 	XDrawLine(mdd, mwin, mgc, mx + 1, my + 1, mx + 1, my + mh - 3);
92 	XSetForeground(mdd, mgc, c2);
93 	XDrawLine(mdd, mwin, mgc, mx + 2, my + mh - 2, mx + mw - 2,
94 		  my + mh - 2);
95 	XDrawLine(mdd, mwin, mgc, mx + mw - 2, my + 2, mx + mw - 2,
96 		  my + mh - 2);
97      }
98 }
99 
100 #define DRAW_HEADER(mdd, mgc, mwin, mx, my, mstr) \
101         AlertDrawHeader(mdd, mgc, mwin, mx, my, mstr, \
102         colorful, cols[2], cols[3], cols[4])
103 static void
AlertDrawHeader(Display * mdd,GC mgc,Window mwin,int mx,int my,const char * mstr,int colorful,unsigned int cb,unsigned int ct1,unsigned int ct2)104 AlertDrawHeader(Display * mdd, GC mgc, Window mwin, int mx, int my,
105 		const char *mstr, int colorful, unsigned int cb,
106 		unsigned int ct1, unsigned int ct2)
107 {
108    int                 len = strlen(mstr);
109 
110    if (colorful)
111      {
112 	XSetForeground(mdd, mgc, cb);
113 	ExDrawString(mdd, mwin, xfs, mgc, mx + 1, my + 1, mstr, len);
114 	ExDrawString(mdd, mwin, xfs, mgc, mx + 2, my + 1, mstr, len);
115 	ExDrawString(mdd, mwin, xfs, mgc, mx + 2, my + 2, mstr, len);
116 	ExDrawString(mdd, mwin, xfs, mgc, mx + 1, my + 2, mstr, len);
117 	XSetForeground(mdd, mgc, ct1);
118 	ExDrawString(mdd, mwin, xfs, mgc, mx - 1, my, mstr, len);
119 	ExDrawString(mdd, mwin, xfs, mgc, mx, my - 1, mstr, len);
120 	ExDrawString(mdd, mwin, xfs, mgc, mx + 1, my, mstr, len);
121 	ExDrawString(mdd, mwin, xfs, mgc, mx, my + 1, mstr, len);
122 	XSetForeground(mdd, mgc, ct2);
123 	ExDrawString(mdd, mwin, xfs, mgc, mx, my, mstr, len);
124      }
125    else
126      {
127 	ExDrawString(mdd, mwin, xfs, mgc, mx, my, mstr, len);
128      }
129 }
130 
131 #define DRAW_STRING(mdd, mgc, mwin, mx, my, mstr, len) \
132         AlertDrawString(mdd, mgc, mwin, mx, my, mstr, len, colorful, cols[3])
133 static void
AlertDrawString(Display * mdd,GC mgc,Window mwin,int mx,int my,const char * mstr,int len,int colorful,unsigned int ct1)134 AlertDrawString(Display * mdd, GC mgc, Window mwin, int mx, int my,
135 		const char *mstr, int len, int colorful, unsigned int ct1)
136 {
137    if (colorful)
138      {
139 	XSetForeground(mdd, mgc, ct1);
140 	ExDrawString(mdd, mwin, xfs, mgc, mx, my, mstr, len);
141      }
142    else
143      {
144 	ExDrawString(mdd, mwin, xfs, mgc, mx, my, mstr, len);
145      }
146 }
147 
148 static char        *
AlertButtonText(int btn,char * buf,unsigned int len,const char * text)149 AlertButtonText(int btn, char *buf, unsigned int len, const char *text)
150 {
151    if (!text)
152       return NULL;
153 
154    Esnprintf(buf, len, "(F%d) %s", btn, text);
155 
156    return buf;
157 }
158 
159 static void
ShowAlert(const char * title,const char * ignore,const char * restart,const char * quit,const char * fmt,va_list args)160 ShowAlert(const char *title,
161 	  const char *ignore, const char *restart, const char *quit,
162 	  const char *fmt, va_list args)
163 {
164    char                text[4096], buf1[64], buf2[64], buf3[64];
165    Window              win, b1 = 0, b2 = 0, b3 = 0, root;
166    Display            *dd;
167    int                 wid, hih, w, h, i, k, mask;
168    XGCValues           gcv;
169    GC                  gc;
170    unsigned int        len;
171    XEvent              ev;
172    XSetWindowAttributes att;
173    XRectangle          rect1, rect2;
174    char                colorful;
175    unsigned long       cols[5];
176    XColor              xcl;
177    Colormap            cmap;
178    int                 cnum, fh, x, y, ww, hh, bw, bh;
179    char               *str1, *str2, *str3, *p;
180    int                 button;
181    char              **missing_charset_list_return, *def_string_return;
182    int                 missing_charset_count_return;
183    XFontStruct       **font_struct_list_return;
184    char              **font_name_list_return;
185 
186 #if 0
187    /* Don't play sound here (maybe if not forked/in signal handler - later) */
188    SoundPlay(SOUND_ALERT);
189 #endif
190 
191    if (!fmt)
192       return;
193 
194    Evsnprintf(text, sizeof(text), fmt, args);
195 
196    /*
197     * We may get here from obscure places like an X-error or signal handler
198     * and things seem to work properly only if we do a new XOpenDisplay().
199     */
200    dd = XOpenDisplay(NULL);
201    if (!dd)
202      {
203 	fprintf(stderr, "%s\n", text);
204 	fflush(stderr);
205 	return;
206      }
207 
208    button = 0;
209 
210    if (!title)
211       title = _("Enlightenment Error");
212    str1 = AlertButtonText(1, buf1, sizeof(buf1), ignore);
213    str2 = AlertButtonText(2, buf2, sizeof(buf2), restart);
214    str3 = AlertButtonText(3, buf3, sizeof(buf3), quit);
215 
216    cnum = 0;
217    colorful = 0;
218    cols[0] = cols[1] = cols[2] = cols[3] = cols[4] = 0;
219    cmap = DefaultColormap(dd, DefaultScreen(dd));
220    if (DefaultDepth(dd, DefaultScreen(dd)) > 4)
221      {
222 	ExSetColor(&xcl, 220, 220, 220);
223 	if (!XAllocColor(dd, cmap, &xcl))
224 	   goto CN;
225 	cols[cnum++] = xcl.pixel;
226 	ExSetColor(&xcl, 160, 160, 160);
227 	if (!XAllocColor(dd, cmap, &xcl))
228 	   goto CN;
229 	cols[cnum++] = xcl.pixel;
230 	ExSetColor(&xcl, 100, 100, 100);
231 	if (!XAllocColor(dd, cmap, &xcl))
232 	   goto CN;
233 	cols[cnum++] = xcl.pixel;
234 	ExSetColor(&xcl, 0, 0, 0);
235 	if (!XAllocColor(dd, cmap, &xcl))
236 	   goto CN;
237 	cols[cnum++] = xcl.pixel;
238 	ExSetColor(&xcl, 255, 255, 255);
239 	if (!XAllocColor(dd, cmap, &xcl))
240 	   goto CN;
241 	cols[cnum++] = xcl.pixel;
242 	colorful = 1;
243      }
244  CN:
245 
246    if (colorful)
247       att.background_pixel = cols[1];
248    else
249       att.background_pixel = BlackPixel(dd, DefaultScreen(dd));
250    if (colorful)
251       att.border_pixel = cols[3];
252    else
253       att.border_pixel = WhitePixel(dd, DefaultScreen(dd));
254    att.backing_store = Always;
255    att.save_under = True;
256    att.override_redirect = True;
257    mask = CWBackPixel | CWBorderPixel | CWOverrideRedirect | CWSaveUnder |
258       CWBackingStore;
259 
260 #if HAVE_COMPOSITE_OVERLAY_WINDOW
261    /*
262     * Intended workings:
263     * Composite extension not enabled (or COW not available?)
264     * - fall back to root
265     * Composite extension enabled
266     * - use COW whether or not compositing is enabled, window mode too
267     */
268    root = XCompositeGetOverlayWindow(dd, DefaultRootWindow(dd));
269    if (root == None)
270 #endif
271      {
272 	root = DefaultRootWindow(dd);
273      }
274 
275    x = y = -100;
276    ww = hh = 1;
277    win = XCreateWindow(dd, root, x, y, ww, hh, 0,
278 		       CopyFromParent, InputOutput, CopyFromParent, mask, &att);
279 
280    gc = XCreateGC(dd, win, 0, &gcv);
281    if (colorful)
282       XSetForeground(dd, gc, cols[3]);
283    else
284       XSetForeground(dd, gc, att.border_pixel);
285 
286    xfs = XCreateFontSet(dd, "fixed",
287 			&missing_charset_list_return,
288 			&missing_charset_count_return, &def_string_return);
289    if (!xfs)
290       goto done;
291 
292    if (missing_charset_list_return)
293       XFreeStringList(missing_charset_list_return);
294 
295    k = XFontsOfFontSet(xfs, &font_struct_list_return, &font_name_list_return);
296    fh = 0;
297    for (i = 0; i < k; i++)
298      {
299 	h = font_struct_list_return[i]->ascent +
300 	   font_struct_list_return[i]->descent;
301 	if (fh < h)
302 	   fh = h;
303      }
304 
305    XSelectInput(dd, win, ExposureMask);
306    XMapWindow(dd, win);
307 
308    XGrabServer(dd);
309 
310    XGrabPointer(dd, win, False, ButtonPressMask | ButtonReleaseMask,
311 		GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
312    XGrabKeyboard(dd, win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
313    XGrabKey(dd, AnyKey, AnyModifier, win, False, GrabModeAsync, GrabModeAsync);
314 
315    XSetInputFocus(dd, win, RevertToPointerRoot, CurrentTime);
316 
317    XSync(dd, False);
318 
319    wid = DisplayWidth(dd, DefaultScreen(dd));
320    hih = DisplayHeight(dd, DefaultScreen(dd));
321    ww = (wid >= 600) ? 600 : (wid / 40) * 40;
322    hh = (hih >= 440) ? 440 : (hih / 40) * 40;
323 
324    for (i = 40; i < ww; i += 40)
325      {
326 	w = i;
327 	h = (i * hh) / ww;
328 	x = (wid - w) >> 1;
329 	y = (hih - h) >> 1;
330 	XMoveResizeWindow(dd, win, x, y, w, h);
331 	DRAW_BOX_OUT(dd, gc, win, 0, 0, w, h);
332 	XSync(dd, False);
333 	SleepUs(20000);
334      }
335    x = (wid - ww) >> 1;
336    y = (hih - hh) >> 1;
337    XMoveResizeWindow(dd, win, x, y, ww, hh);
338    XSync(dd, False);
339 
340    bw = 0;
341    if (str1)
342      {
343 	ExTextExtents(xfs, str1, strlen(str1), &rect1, &rect2);
344 	bw = (rect2.width > bw) ? rect2.width : bw;
345      }
346    if (str2)
347      {
348 	ExTextExtents(xfs, str2, strlen(str2), &rect1, &rect2);
349 	bw = (rect2.width > bw) ? rect2.width : bw;
350      }
351    if (str3)
352      {
353 	ExTextExtents(xfs, str3, strlen(str3), &rect1, &rect2);
354 	bw = (rect2.width > bw) ? rect2.width : bw;
355      }
356    bw += 20;
357    bh = fh + 10;
358 
359 #define BX(i) (5 + (((ww - bw - 10) * (i)) / 2))
360 #define BY    (hh - bh - 5)
361 
362    if (str1)
363      {
364 	b1 = XCreateWindow(dd, win, BX(0), BY, bw, bh, 0, CopyFromParent,
365 			   InputOutput, CopyFromParent, mask, &att);
366 	XMapWindow(dd, b1);
367      }
368    if (str2)
369      {
370 	b2 = XCreateWindow(dd, win, BX(1), BY, bw, bh, 0, CopyFromParent,
371 			   InputOutput, CopyFromParent, mask, &att);
372 	XMapWindow(dd, b2);
373      }
374    if (str3)
375      {
376 	b3 = XCreateWindow(dd, win, BX(2), BY, bw, bh, 0, CopyFromParent,
377 			   InputOutput, CopyFromParent, mask, &att);
378 	XMapWindow(dd, b3);
379      }
380    XSync(dd, False);
381 
382    button = 0;
383    for (; button == 0;)
384      {
385 	XNextEvent(dd, &ev);
386 
387 	switch (ev.type)
388 	  {
389 	  case KeyPress:
390 	     if (str1 && ev.xkey.keycode == XKeysymToKeycode(dd, XK_F1))
391 	       {
392 		  DRAW_BOX_IN(dd, gc, b1, 0, 0, bw, bh);
393 		  XSync(dd, False);
394 		  SleepUs(500000);
395 		  DRAW_BOX_OUT(dd, gc, b1, 0, 0, bw, bh);
396 		  button = 1;
397 		  goto do_sync;
398 	       }
399 	     if (str2 && ev.xkey.keycode == XKeysymToKeycode(dd, XK_F2))
400 	       {
401 		  DRAW_BOX_IN(dd, gc, b2, 0, 0, bw, bh);
402 		  XSync(dd, False);
403 		  SleepUs(500000);
404 		  DRAW_BOX_OUT(dd, gc, b2, 0, 0, bw, bh);
405 		  button = 2;
406 		  goto do_sync;
407 	       }
408 	     if (str3 && ev.xkey.keycode == XKeysymToKeycode(dd, XK_F3))
409 	       {
410 		  DRAW_BOX_IN(dd, gc, b3, 0, 0, bw, bh);
411 		  XSync(dd, False);
412 		  SleepUs(500000);
413 		  DRAW_BOX_OUT(dd, gc, b3, 0, 0, bw, bh);
414 		  button = 3;
415 		  goto do_sync;
416 	       }
417 	     break;
418 
419 	  case ButtonPress:
420 	     if (!(ev.xbutton.y >= BY && ev.xbutton.y < BY + bh))
421 		break;
422 
423 	     x = BX(0);
424 	     if (b1 && ev.xbutton.x >= x && ev.xbutton.x < x + bw)
425 	       {
426 		  DRAW_BOX_IN(dd, gc, b1, 0, 0, bw, bh);
427 		  goto do_sync;
428 	       }
429 	     x = BX(1);
430 	     if (b2 && ev.xbutton.x >= x && ev.xbutton.x < x + bw)
431 	       {
432 		  DRAW_BOX_IN(dd, gc, b2, 0, 0, bw, bh);
433 		  goto do_sync;
434 	       }
435 	     x = BX(2);
436 	     if (b3 && ev.xbutton.x >= x && ev.xbutton.x < x + bw)
437 	       {
438 		  DRAW_BOX_IN(dd, gc, b3, 0, 0, bw, bh);
439 		  goto do_sync;
440 	       }
441 	     break;
442 
443 	  case ButtonRelease:
444 	     if (!(ev.xbutton.y >= BY && ev.xbutton.y < BY + bh))
445 		break;
446 
447 	     x = BX(0);
448 	     if (b1 && ev.xbutton.x >= x && ev.xbutton.x < x + bw)
449 	       {
450 		  DRAW_BOX_OUT(dd, gc, b1, 0, 0, bw, bh);
451 		  button = 1;
452 		  goto do_sync;
453 	       }
454 	     x = BX(1);
455 	     if (b2 && ev.xbutton.x >= x && ev.xbutton.x < x + bw)
456 	       {
457 		  DRAW_BOX_OUT(dd, gc, b2, 0, 0, bw, bh);
458 		  button = 2;
459 		  goto do_sync;
460 	       }
461 	     x = BX(2);
462 	     if (b3 && ev.xbutton.x >= x && ev.xbutton.x < x + bw)
463 	       {
464 		  DRAW_BOX_OUT(dd, gc, b3, 0, 0, bw, bh);
465 		  button = 3;
466 		  goto do_sync;
467 	       }
468 	     break;
469 
470 	  case Expose:
471 	     /* Flush all other Expose events */
472 	     while (XCheckTypedWindowEvent(dd, ev.xexpose.window, Expose, &ev))
473 		;
474 
475 	     ExTextExtents(xfs, title, strlen(title), &rect1, &rect2);
476 	     w = rect2.width;
477 
478 	     DRAW_HEADER(dd, gc, win, (ww - w) / 2, 5 - rect2.y, title);
479 	     DRAW_BOX_OUT(dd, gc, win, 0, 0, ww, bh);
480 	     DRAW_BOX_OUT(dd, gc, win, 0, bh - 1, ww, hh - fh - fh - 30 + 2);
481 	     DRAW_BOX_OUT(dd, gc, win, 0, hh - fh - 20, ww, fh + 20);
482 	     k = bh;
483 	     for (p = text;; p += len + 1)
484 	       {
485 		  len = strcspn(p, "\n");
486 		  DRAW_STRING(dd, gc, win, 6, 6 + k + fh, p, len);
487 		  k += fh + 2;
488 		  if (p[len] == '\0')
489 		     break;
490 	       }
491 	     if (str1)
492 	       {
493 		  ExTextExtents(xfs, str1, strlen(str1), &rect1, &rect2);
494 		  w = rect2.width;
495 		  DRAW_HEADER(dd, gc, b1, (bw - w) / 2, 5 - rect2.y, str1);
496 		  DRAW_BOX_OUT(dd, gc, b1, 0, 0, bw, bh);
497 		  DRAW_THIN_BOX_IN(dd, gc, win,
498 				   BX(0) - 2, BY - 2, bw + 4, bh + 4);
499 	       }
500 	     if (str2)
501 	       {
502 		  ExTextExtents(xfs, str2, strlen(str2), &rect1, &rect2);
503 		  w = rect2.width;
504 		  DRAW_HEADER(dd, gc, b2, (bw - w) / 2, 5 - rect2.y, str2);
505 		  DRAW_BOX_OUT(dd, gc, b2, 0, 0, bw, bh);
506 		  DRAW_THIN_BOX_IN(dd, gc, win,
507 				   BX(1) - 2, BY - 2, bw + 4, bh + 4);
508 	       }
509 	     if (str3)
510 	       {
511 		  ExTextExtents(xfs, str3, strlen(str3), &rect1, &rect2);
512 		  w = rect2.width;
513 		  DRAW_HEADER(dd, gc, b3, (bw - w) / 2, 5 - rect2.y, str3);
514 		  DRAW_BOX_OUT(dd, gc, b3, 0, 0, bw, bh);
515 		  DRAW_THIN_BOX_IN(dd, gc, win,
516 				   BX(2) - 2, BY - 2, bw + 4, bh + 4);
517 	       }
518 	   do_sync:
519 	     XSync(dd, False);
520 	     break;
521 
522 	  default:
523 	     break;
524 	  }
525      }
526 
527    XFreeFontSet(dd, xfs);
528  done:
529    XUngrabServer(dd);
530 #if HAVE_COMPOSITE_OVERLAY_WINDOW
531    /* Force damage on root window where GSOD is/was rendered */
532    if (root != DefaultRootWindow(dd))
533      {
534 	XReparentWindow(dd, win, DefaultRootWindow(dd), x, y);
535 	XUnmapWindow(dd, win);
536 	XSync(dd, False);
537 	SleepUs(20000);
538      }
539 #endif
540    XDestroyWindow(dd, win);
541    XFreeGC(dd, gc);
542    if (cnum > 0)
543       XFreeColors(dd, cmap, cols, cnum, 0);
544    XCloseDisplay(dd);
545 
546    switch (button)
547      {
548      default:
549      case 1:
550 	break;
551      case 2:
552 	SessionExit(EEXIT_RESTART, NULL);
553 	break;
554      case 3:
555 	SessionExit(EEXIT_EXIT, NULL);
556 	break;
557      }
558 }
559 
560 void
AlertX(const char * title,const char * ignore,const char * restart,const char * quit,const char * fmt,...)561 AlertX(const char *title, const char *ignore,
562        const char *restart, const char *quit, const char *fmt, ...)
563 {
564    va_list             args;
565 
566    va_start(args, fmt);
567    ShowAlert(title, ignore, restart, quit, fmt, args);
568    va_end(args);
569 }
570 
571 void
Alert(const char * fmt,...)572 Alert(const char *fmt, ...)
573 {
574    va_list             args;
575 
576    va_start(args, fmt);
577    ShowAlert(_("Enlightenment Message Dialog"), _("Ignore this"),
578 	     _("Restart Enlightenment"), _("Quit Enlightenment"), fmt, args);
579    va_end(args);
580 }
581 
582 void
AlertOK(const char * fmt,...)583 AlertOK(const char *fmt, ...)
584 {
585    va_list             args;
586 
587    va_start(args, fmt);
588    ShowAlert(_("Attention !!!"), _("OK"), NULL, NULL, fmt, args);
589    va_end(args);
590 }
591