e16/src/alert.c

600 lines
16 KiB
C

/*
* Copyright (C) 2000 Carsten Haitzler, Geoff Harrison and various contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies of the Software, its documentation and marketing & publicity
* materials, and acknowledgment shall be given in the documentation, materials
* and software packages that this Software was used.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "E.h"
static void ShowAlert(char *text);
static void AlertHandleClick(int button);
static int (*IgnoreFunction) (void *) = NULL;
static void *IgnoreParams = NULL;
static char *IgnoreText = NULL;
static int (*RestartFunction) (void *) = NULL;
static void *RestartParams = NULL;
static char *RestartText = NULL;
static int (*ExitFunction) (void *) = NULL;
static void *ExitParams = NULL;
static char *ExitText = NULL;
static char *TitleText = NULL;
int call_level;
int debug_level;
char *call_stack[1024];
void
Alert(char *fmt, ...)
{
char text[10240];
va_list ap;
EDBUG(7, "Alert");
SC_Kill();
va_start(ap, fmt);
/*
* #ifdef __USE_GNU
*/
Evsnprintf(text, 10240, fmt, ap);
/*
* #else
* vsprintf(text, fmt, ap);
* #endif
*/
va_end(ap);
AUDIO_PLAY("SOUND_ALERT");
ShowAlert(text);
EDBUG_RETURN_;
}
void
AssignTitleText(char *text)
{
EDBUG(7, "AssignTitleText");
if (TitleText)
Efree(TitleText);
TitleText = NULL;
TitleText = duplicate(text);
EDBUG_RETURN_;
}
void
AssignIgnoreText(char *text)
{
EDBUG(7, "AssignIgnoreText");
if (IgnoreText)
Efree(IgnoreText);
IgnoreText = NULL;
IgnoreText = Emalloc(strlen(text) + 6);
sprintf(IgnoreText, "(F1) %s", text);
EDBUG_RETURN_;
}
void
AssignRestartText(char *text)
{
EDBUG(7, "AssignRestartText");
if (RestartText)
Efree(RestartText);
RestartText = NULL;
RestartText = Emalloc(strlen(text) + 6);
sprintf(RestartText, "(F2) %s", text);
EDBUG_RETURN_;
}
void
AssignExitText(char *text)
{
EDBUG(7, "AssignExitText");
if (ExitText)
Efree(ExitText);
ExitText = NULL;
ExitText = Emalloc(strlen(text) + 6);
sprintf(ExitText, "(F3) %s", text);
EDBUG_RETURN_;
}
void
AssignIgnoreFunction(int (*FunctionToAssign) (void *), void *params)
{
EDBUG(7, "AssignIgnoreFunction");
IgnoreFunction = FunctionToAssign;
IgnoreParams = params;
EDBUG_RETURN_;
}
void
AssignRestartFunction(int (*FunctionToAssign) (void *), void *params)
{
EDBUG(7, "AssignRestartFunction");
RestartFunction = FunctionToAssign;
RestartParams = params;
EDBUG_RETURN_;
}
void
AssignExitFunction(int (*FunctionToAssign) (void *), void *params)
{
EDBUG(7, "AssignExitFunction");
ExitFunction = FunctionToAssign;
ExitParams = params;
EDBUG_RETURN_;
}
static void
ShowAlert(char *text)
{
Window win = 0, b1 = 0, b2 = 0, b3 = 0;
Display *dd;
int wid, hih, w, h, i, j, k, mask;
XGCValues gcv;
GC gc;
char line[1024];
XEvent ev;
XFontStruct *xfs;
Font font;
XSetWindowAttributes att;
char colorful;
XColor xcl;
Colormap cmap;
int cols[256];
int cnum, r, g, b, fh, x, y, ww, hh, mh;
static char *title = NULL, *str1 = NULL, *str2 = NULL, *str3 = NULL;
KeyCode key;
EDBUG(8, "ShowAlert");
if (!text)
EDBUG_RETURN_;
dd = XOpenDisplay(NULL);
if (!dd)
{
fprintf(stderr, text);
fflush(stderr);
EDBUG_RETURN_;
}
title = TitleText;
str1 = IgnoreText;
str2 = RestartText;
str3 = ExitText;
if (!title)
title = _("Enlightenment Error");
if (!str1)
str1 = _("Ignore");
if (!str2)
str2 = _("Restart");
if (!str3)
str3 = _("Exit");
#define DRAW_BOX_OUT(mdd, mgc, mwin, mx, my, mw, mh) \
if (colorful) { \
XSetForeground(mdd, mgc, cols[3]); \
XDrawRectangle(mdd, mwin, mgc, mx, my, mw - 1, mh - 1); \
XSetForeground(mdd, mgc, cols[0]); \
XDrawLine(mdd, mwin, mgc, mx + 1, my + 1, mx + mw - 3, my + 1); \
XDrawLine(mdd, mwin, mgc, mx + 1, my + 1, mx + 1, my + mh - 3); \
XSetForeground(mdd, mgc, cols[2]); \
XDrawLine(mdd, mwin, mgc, mx + 2, my + mh - 2, mx + mw - 2, my + mh - 2); \
XDrawLine(mdd, mwin, mgc, mx + mw - 2, my + 2, mx + mw - 2, my + mh - 2); \
} else { \
XDrawRectangle(mdd, mwin, mgc, mx, my, mw - 1, mh - 1); \
}
#define DRAW_BOX_IN(mdd, mgc, mwin, mx, my, mw, mh) \
if (colorful) { \
XSetForeground(mdd, mgc, cols[3]); \
XDrawRectangle(mdd, mwin, mgc, mx, my, mw - 1, mh - 1); \
XSetForeground(mdd, mgc, cols[2]); \
XDrawLine(mdd, mwin, mgc, mx + 1, my + 1, mx + mw - 3, my + 1); \
XDrawLine(mdd, mwin, mgc, mx + 1, my + 1, mx + 1, my + mh - 3); \
XSetForeground(mdd, mgc, cols[0]); \
XDrawLine(mdd, mwin, mgc, mx + 2, my + mh - 2, mx + mw - 2, my + mh - 2); \
XDrawLine(mdd, mwin, mgc, mx + mw - 2, my + 2, mx + mw - 2, my + mh - 2); \
} else { \
XDrawRectangle(mdd, mwin, mgc, mx, my, mw - 1, mh - 1); \
}
#define DRAW_THIN_BOX_IN(mdd, mgc, mwin, mx, my, mw, mh) \
if (colorful) { \
XSetForeground(mdd, mgc, cols[2]); \
XDrawLine(mdd, mwin, mgc, mx + 1, my + 1, mx + mw - 3, my + 1); \
XDrawLine(mdd, mwin, mgc, mx + 1, my + 1, mx + 1, my + mh - 3); \
XSetForeground(mdd, mgc, cols[0]); \
XDrawLine(mdd, mwin, mgc, mx + 2, my + mh - 2, mx + mw - 2, my + mh - 2); \
XDrawLine(mdd, mwin, mgc, mx + mw - 2, my + 2, mx + mw - 2, my + mh - 2); \
}
#define DRAW_HEADER(mdd, mgc, mwin, mx, my, mstr) \
if (colorful) { \
XSetForeground(mdd, mgc, cols[2]); \
XDrawString(mdd, mwin, mgc, mx + 1, my + 1, mstr, strlen(mstr)); \
XDrawString(mdd, mwin, mgc, mx + 2, my + 1, mstr, strlen(mstr)); \
XDrawString(mdd, mwin, mgc, mx + 2, my + 2, mstr, strlen(mstr)); \
XDrawString(mdd, mwin, mgc, mx + 1, my + 2, mstr, strlen(mstr)); \
XSetForeground(mdd, mgc, cols[3]); \
XDrawString(mdd, mwin, mgc, mx - 1, my, mstr, strlen(mstr)); \
XDrawString(mdd, mwin, mgc, mx, my - 1, mstr, strlen(mstr)); \
XDrawString(mdd, mwin, mgc, mx + 1, my, mstr, strlen(mstr)); \
XDrawString(mdd, mwin, mgc, mx, my + 1, mstr, strlen(mstr)); \
XSetForeground(mdd, mgc, cols[4]); \
XDrawString(mdd, mwin, mgc, mx, my, mstr, strlen(mstr)); \
} else { \
XDrawString(mdd, mwin, mgc, mx, my, mstr, strlen(mstr)); \
}
#define DRAW_STRING(mdd, mgc, mwin, mx, my, mstr) \
if (colorful) { \
XSetForeground(mdd, mgc, cols[3]); \
XDrawString(mdd, mwin, mgc, mx, my, mstr, strlen(mstr)); \
} else { \
XDrawString(mdd, mwin, mgc, mx, my, mstr, strlen(mstr)); \
}
#define ALLOC_COLOR(d,m,c) \
if (!XAllocColor(d, m, c)) \
{ \
colorful = 0; \
goto CN; \
}
cnum = 0;
cmap = 0;
colorful = 0;
if (DefaultDepth(dd, DefaultScreen(dd)) > 4)
colorful = 1;
if (colorful)
{
cmap = DefaultColormap(dd, DefaultScreen(dd));
r = 220;
g = 220;
b = 220;
xcl.red = (r << 8) | r;
xcl.green = (g << 8) | g;
xcl.blue = (b << 8) | b;
ALLOC_COLOR(dd, cmap, &xcl);
cols[cnum++] = xcl.pixel;
r = 160;
g = 160;
b = 160;
xcl.red = (r << 8) | r;
xcl.green = (g << 8) | g;
xcl.blue = (b << 8) | b;
ALLOC_COLOR(dd, cmap, &xcl);
cols[cnum++] = xcl.pixel;
r = 100;
g = 100;
b = 100;
xcl.red = (r << 8) | r;
xcl.green = (g << 8) | g;
xcl.blue = (b << 8) | b;
ALLOC_COLOR(dd, cmap, &xcl);
cols[cnum++] = xcl.pixel;
r = 0;
g = 0;
b = 0;
xcl.red = (r << 8) | r;
xcl.green = (g << 8) | g;
xcl.blue = (b << 8) | b;
ALLOC_COLOR(dd, cmap, &xcl);
cols[cnum++] = xcl.pixel;
r = 255;
g = 255;
b = 255;
xcl.red = (r << 8) | r;
xcl.green = (g << 8) | g;
xcl.blue = (b << 8) | b;
ALLOC_COLOR(dd, cmap, &xcl);
cols[cnum++] = xcl.pixel;
}
CN:
wid = DisplayWidth(dd, DefaultScreen(dd));
hih = DisplayHeight(dd, DefaultScreen(dd));
w = (wid - 600) / 2;
h = (hih - 440) / 2;
mask =
CWBackPixel | CWBorderPixel | CWOverrideRedirect | CWSaveUnder |
CWBackingStore;
if (colorful)
att.background_pixel = cols[1];
else
att.background_pixel = BlackPixel(dd, DefaultScreen(dd));
if (colorful)
att.border_pixel = cols[3];
else
att.border_pixel = WhitePixel(dd, DefaultScreen(dd));
att.backing_store = Always;
att.save_under = True;
att.override_redirect = True;
win =
XCreateWindow(dd, DefaultRootWindow(dd), -100, -100, 1, 1, 0,
DefaultDepth(dd, DefaultScreen(dd)), InputOutput,
DefaultVisual(dd, DefaultScreen(dd)), mask, &att);
if (sscanf(str1, "%s", line) > 0)
{
b1 =
XCreateWindow(dd, win, -100, -100, 1, 1, 0,
DefaultDepth(dd, DefaultScreen(dd)), InputOutput,
DefaultVisual(dd, DefaultScreen(dd)), mask, &att);
EMapWindow(dd, b1);
}
if (sscanf(str2, "%s", line) > 0)
{
b2 =
XCreateWindow(dd, win, -100, -100, 1, 1, 0,
DefaultDepth(dd, DefaultScreen(dd)), InputOutput,
DefaultVisual(dd, DefaultScreen(dd)), mask, &att);
EMapWindow(dd, b2);
}
if (sscanf(str3, "%s", line) > 0)
{
b3 =
XCreateWindow(dd, win, -100, -100, 1, 1, 0,
DefaultDepth(dd, DefaultScreen(dd)), InputOutput,
DefaultVisual(dd, DefaultScreen(dd)), mask, &att);
EMapWindow(dd, b3);
}
gc = XCreateGC(dd, win, 0, &gcv);
if (colorful)
XSetForeground(dd, gc, cols[3]);
else
XSetForeground(dd, gc, att.border_pixel);
fh = 0;
xfs = NULL;
if (!xfs)
{
xfs = XLoadQueryFont(dd, "-*-helvetica-*-r-*-*-12-*-*-*-*-*-*-*");
}
if (!xfs)
{
xfs = XLoadQueryFont(dd, "fixed");
}
font = xfs->fid;
fh = xfs->ascent + xfs->descent;
XSetFont(dd, gc, font);
XMapWindow(dd, win);
XGrabPointer(dd, win, True, ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
XGrabKeyboard(dd, win, True, GrabModeAsync, GrabModeAsync, CurrentTime);
XSetInputFocus(dd, win, RevertToPointerRoot, CurrentTime);
XGrabServer(dd);
XSync(dd, False);
for (i = 0; i < 600; i += 40)
{
ww = i;
hh = (i * 440) / 600;
x = (wid - ww) >> 1;
y = (hih - hh) >> 1;
XMoveResizeWindow(dd, win, x, y, ww, hh);
DRAW_BOX_OUT(dd, gc, win, 0, 0, ww, hh);
XSync(dd, False);
}
ww = 600;
hh = 440;
x = (wid - 600) >> 1;
y = (hih - 440) >> 1;
XMoveResizeWindow(dd, win, x, y, ww, hh);
XUngrabServer(dd);
XSync(dd, False);
mh = XTextWidth(xfs, str1, strlen(str1)) + 10;
h = XTextWidth(xfs, str2, strlen(str2)) + 10;
if (h > mh)
mh = h;
h = XTextWidth(xfs, str3, strlen(str3)) + 10;
if (h > mh)
mh = h;
if (sscanf(str1, "%s", line) > 0)
{
h = XTextWidth(xfs, str1, strlen(str1));
w = 10 + (((580 - mh) * 0) / 4);
XMoveResizeWindow(dd, b1, w - 5, 440 - 15 - fh, mh + 10, fh + 10);
XSelectInput(dd, b1,
ButtonPressMask | ButtonReleaseMask | ExposureMask);
}
if (sscanf(str2, "%s", line) > 0)
{
h = XTextWidth(xfs, str2, strlen(str2));
w = 10 + (((580 - mh) * 1) / 2);
XMoveResizeWindow(dd, b2, w - 5, 440 - 15 - fh, mh + 10, fh + 10);
XSelectInput(dd, b2,
ButtonPressMask | ButtonReleaseMask | ExposureMask);
}
if (sscanf(str3, "%s", line) > 0)
{
h = XTextWidth(xfs, str3, strlen(str3));
w = 10 + (((580 - mh) * 2) / 2);
XMoveResizeWindow(dd, b3, w - 5, 440 - 15 - fh, mh + 10, fh + 10);
XSelectInput(dd, b3,
ButtonPressMask | ButtonReleaseMask | ExposureMask);
}
XSync(dd, False);
XSelectInput(dd, win, KeyPressMask | KeyReleaseMask | ExposureMask);
#define DRAW_ALERT \
w = XTextWidth(xfs, title, strlen(title)); \
DRAW_HEADER(dd, gc, win, (600 - w) / 2, 5 + xfs->ascent, title); \
DRAW_BOX_OUT(dd, gc, win, 0, 0, ww, fh + 10); \
DRAW_BOX_OUT(dd, gc, win, 0, fh + 10 - 1, ww, hh - fh - fh - 30 + 2); \
DRAW_BOX_OUT(dd, gc, win, 0, 440 - fh - 20, ww, fh + 20); \
i = 0; \
j = 0; \
k = fh + 10; \
while (text[i]) { \
line[j++] = text[i++]; \
if (line[j - 1] == '\n') { \
line[j - 1] = 0; \
j = 0; \
DRAW_STRING(dd, gc, win, 6, 6 + k + fh, line); \
k += fh + 2; \
} \
} \
if (sscanf(str1, "%s", line) > 0) \
{ \
h = XTextWidth(xfs, str1, strlen(str1)); \
w = 10 + (((580 - mh) * 0) / 4); \
DRAW_HEADER(dd, gc, b1, 5 + (mh - h) / 2, fh + 5 - xfs->descent, str1); \
DRAW_BOX_OUT(dd, gc, b1, 0, 0, mh + 10, fh + 10); \
DRAW_THIN_BOX_IN(dd, gc, win, w - 7, 440 - 17 - fh, mh + 14, fh + 14); \
} \
if (sscanf(str2, "%s", line) > 0) \
{ \
h = XTextWidth(xfs, str2, strlen(str2)); \
w = 10 + (((580 - mh) * 1) / 2); \
DRAW_HEADER(dd, gc, b2, 5 + (mh - h) / 2, fh + 5 - xfs->descent, str2); \
DRAW_BOX_OUT(dd, gc, b2, 0, 0, mh + 10, fh + 10); \
DRAW_THIN_BOX_IN(dd, gc, win, w - 7, 440 - 17 - fh, mh + 14, fh + 14); \
} \
if (sscanf(str3, "%s", line) > 0) \
{ \
h = XTextWidth(xfs, str3, strlen(str3)); \
w = 10 + (((580 - mh) * 2) / 2); \
DRAW_HEADER(dd, gc, b3, 5 + (mh - h) / 2, fh + 5 - xfs->descent, str3); \
DRAW_BOX_OUT(dd, gc, b3, 0, 0, mh + 10, fh + 10); \
DRAW_THIN_BOX_IN(dd, gc, win, w - 7, 440 - 17 - fh, mh + 14, fh + 14); \
XSync(dd, False); \
}
DRAW_ALERT;
w = 1;
while (w == 1)
{
XNextEvent(dd, &ev);
switch (ev.type)
{
case KeyPress:
key = XKeysymToKeycode(dd, XStringToKeysym("F1"));
if (key == ev.xkey.keycode)
{
DRAW_BOX_IN(dd, gc, b1, 0, 0, mh + 10, fh + 10);
XSync(dd, False);
sleep(1);
DRAW_BOX_OUT(dd, gc, b1, 0, 0, mh + 10, fh + 10);
XSync(dd, False);
AlertHandleClick(1);
w = 0;
}
key = XKeysymToKeycode(dd, XStringToKeysym("F2"));
if (key == ev.xkey.keycode)
{
DRAW_BOX_IN(dd, gc, b2, 0, 0, mh + 10, fh + 10);
XSync(dd, False);
sleep(1);
DRAW_BOX_OUT(dd, gc, b2, 0, 0, mh + 10, fh + 10);
XSync(dd, False);
AlertHandleClick(2);
w = 0;
}
key = XKeysymToKeycode(dd, XStringToKeysym("F3"));
if (key == ev.xkey.keycode)
{
DRAW_BOX_IN(dd, gc, b3, 0, 0, mh + 10, fh + 10);
XSync(dd, False);
sleep(1);
DRAW_BOX_OUT(dd, gc, b3, 0, 0, mh + 10, fh + 10);
XSync(dd, False);
AlertHandleClick(3);
w = 0;
}
break;
case ButtonPress:
if (ev.xbutton.window == b1)
{
DRAW_BOX_IN(dd, gc, b1, 0, 0, mh + 10, fh + 10);
}
else if (ev.xbutton.window == b2)
{
DRAW_BOX_IN(dd, gc, b2, 0, 0, mh + 10, fh + 10);
}
else if (ev.xbutton.window == b3)
{
DRAW_BOX_IN(dd, gc, b3, 0, 0, mh + 10, fh + 10);
}
w = 1;
XSync(dd, False);
break;
case ButtonRelease:
if (ev.xbutton.window == b1)
{
DRAW_BOX_OUT(dd, gc, b1, 0, 0, mh + 10, fh + 10);
XSync(dd, False);
AlertHandleClick(1);
w = 0;
}
else if (ev.xbutton.window == b2)
{
DRAW_BOX_OUT(dd, gc, b2, 0, 0, mh + 10, fh + 10);
XSync(dd, False);
AlertHandleClick(2);
w = 0;
}
else if (ev.xbutton.window == b3)
{
DRAW_BOX_OUT(dd, gc, b3, 0, 0, mh + 10, fh + 10);
XSync(dd, False);
AlertHandleClick(3);
w = 0;
}
break;
case Expose:
DRAW_ALERT;
w = 1;
break;
default:
break;
}
}
XDestroyWindow(dd, win);
XFreeGC(dd, gc);
XFreeFont(dd, xfs);
XUnloadFont(dd, font);
if (cnum > 0)
XFreeColors(dd, cmap, (unsigned long *)cols, cnum, 0);
XCloseDisplay(dd);
EDBUG_RETURN_;
}
static void
AlertHandleClick(int button)
{
EDBUG(9, "AlertHandleClick");
switch (button)
{
case 1:
if (IgnoreFunction)
(*(IgnoreFunction)) (IgnoreParams);
break;
case 2:
if (RestartFunction)
(*(RestartFunction)) (RestartParams);
break;
case 3:
if (ExitFunction)
(*(ExitFunction)) (ExitParams);
break;
default:
break;
}
EDBUG_RETURN_;
}