1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-20 21:08:08 +01:00

Added the crash dialog panel

This commit is contained in:
dan
1999-04-16 01:12:45 +00:00
parent e96d9a99ee
commit c98f229d9c
18 changed files with 353 additions and 27 deletions

View File

@@ -2,6 +2,7 @@
* Window Maker window manager
*
* Copyright (c) 1997, 1998 Alfredo K. Kojima
* Copyright (c) 1999 Dan Pascu
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -76,6 +77,8 @@ extern const char * const sys_siglist[];
/****** Global Variables ******/
extern char **Arguments;
extern WPreferences wPreferences;
extern WDDomain *WDWindowMaker;
@@ -154,6 +157,256 @@ static void manageAllWindows();
extern void NotifyDeadProcess(pid_t pid, unsigned char status);
typedef struct _CrashPanel {
WMWindow *win; /* main window */
WMLabel *iconL; /* application icon */
WMLabel *nameL; /* title of panel */
WMFrame *sepF; /* separator frame */
WMLabel *noteL; /* Title of note */
WMLabel *note2L; /* body of note with what happened */
WMFrame *whatF; /* "what to do next" frame */
WMPopUpButton *whatP; /* action selection popup button */
WMButton *okB; /* ok button */
Bool done; /* if finished with this dialog */
int action; /* what to do after */
KeyCode retKey;
} CrashPanel;
enum {
WMAbort=0,
WMRestart,
WMStartAlternate
};
static void
handleKeyPress(XEvent *event, void *clientData)
{
CrashPanel *panel = (CrashPanel*)clientData;
if (event->xkey.keycode == panel->retKey) {
WMPerformButtonClick(panel->okB);
}
}
static void
buttonCallback(void *self, void *clientData)
{
CrashPanel *panel = (CrashPanel*)clientData;
panel->done = True;
}
static void
setAction(void *self, void *clientData)
{
WMPopUpButton *pop = (WMPopUpButton*)self;
CrashPanel *panel = (CrashPanel*)clientData;
panel->action = WMGetPopUpButtonSelectedItem(pop);
}
static WMPixmap*
getWindowMakerIconImage(WMScreen *scr)
{
proplist_t dict, key, option, value=NULL;
WMPixmap *pix=NULL;
char *path;
PLSetStringCmpHook(NULL);
key = PLMakeString("Logo.WMPanel");
option = PLMakeString("Icon");
dict = PLGetDictionaryEntry(WDWindowAttributes->dictionary, key);
if (dict) {
value = PLGetDictionaryEntry(dict, option);
}
PLRelease(key);
PLRelease(option);
PLSetStringCmpHook(StringCompareHook);
if (value && PLIsString(value)) {
path = FindImage(wPreferences.icon_path, PLGetString(value));
if (path) {
RImage *image;
image = RLoadImage(WMScreenRContext(scr), path, 0);
if (image) {
pix = WMCreatePixmapFromRImage(scr, image, 0);
RDestroyImage(image);
}
free(path);
}
}
return pix;
}
#define PWIDTH 295
#define PHEIGHT 345
static int
showCrashPanel(int whatSig)
{
CrashPanel *panel;
WMScreen *scr;
WMFont *font;
WMPixmap *logo;
Display *newdpy;
int screen_no, scr_width, scr_height;
int action;
char buf[256];
panel = wmalloc(sizeof(CrashPanel));
memset(panel, 0, sizeof(CrashPanel));
/* Close the X connection and open a new one. This is to avoid messing
* Xlib because we call to Xlib functions in a signal handler.
*/
XCloseDisplay(dpy);
newdpy = XOpenDisplay("");
if (!newdpy) {
wfatal(_("cannot open connection for crashing dialog panel. Aborting."));
return WMAbort;
}
screen_no = DefaultScreen(newdpy);
scr_width = WidthOfScreen(ScreenOfDisplay(newdpy, screen_no));
scr_height = HeightOfScreen(ScreenOfDisplay(newdpy, screen_no));
scr = WMCreateScreen(newdpy, screen_no);
if (!scr) {
wfatal(_("cannot open connection for crashing dialog panel. Aborting."));
return WMAbort;
}
panel->retKey = XKeysymToKeycode(newdpy, XK_Return);
panel->win = WMCreateWindow(scr, "crashingDialog");
WMResizeWidget(panel->win, PWIDTH, PHEIGHT);
WMMoveWidget(panel->win, (scr_width - PWIDTH)/2, (scr_height - PHEIGHT)/2);
logo = getWindowMakerIconImage(scr);
if (logo) {
panel->iconL = WMCreateLabel(panel->win);
WMResizeWidget(panel->iconL, 64, 64);
WMMoveWidget(panel->iconL, 10, 10);
WMSetLabelImagePosition(panel->iconL, WIPImageOnly);
WMSetLabelImage(panel->iconL, logo);
}
panel->nameL = WMCreateLabel(panel->win);
WMResizeWidget(panel->nameL, 190, 18);
WMMoveWidget(panel->nameL, 80, 35);
WMSetLabelTextAlignment(panel->nameL, WALeft);
font = WMBoldSystemFontOfSize(scr, 18);
WMSetLabelFont(panel->nameL, font);
WMReleaseFont(font);
WMSetLabelText(panel->nameL, _("Fatal error"));
panel->sepF = WMCreateFrame(panel->win);
WMResizeWidget(panel->sepF, PWIDTH+4, 2);
WMMoveWidget(panel->sepF, -2, 80);
panel->noteL = WMCreateLabel(panel->win);
WMResizeWidget(panel->noteL, PWIDTH-20, 40);
WMMoveWidget(panel->noteL, 10, 90);
WMSetLabelTextAlignment(panel->noteL, WAJustified);
#ifdef SYS_SIGLIST_DECLARED
sprintf(buf, _("Window Maker received signal %i\n(%s)."),
whatSig, sys_siglist[whatSig]);
#else
sprintf(buf, _("Window Maker received signal %i."), whatSig);
#endif
WMSetLabelText(panel->noteL, buf);
panel->note2L = WMCreateLabel(panel->win);
WMResizeWidget(panel->note2L, PWIDTH-20, 100);
WMMoveWidget(panel->note2L, 10, 130);
WMSetLabelTextAlignment(panel->note2L, WALeft);
WMSetLabelText(panel->note2L,
_(" This fatal error occured probably due to a bug."
" Please fill the included BUGFORM and "
"report it to bugs@windowmaker.org."));
panel->whatF = WMCreateFrame(panel->win);
WMResizeWidget(panel->whatF, PWIDTH-20, 50);
WMMoveWidget(panel->whatF, 10, 240);
WMSetFrameTitle(panel->whatF, _("What do you want to do now?"));
panel->whatP = WMCreatePopUpButton(panel->whatF);
WMResizeWidget(panel->whatP, PWIDTH-20-70, 20);
WMMoveWidget(panel->whatP, 35, 20);
WMSetPopUpButtonPullsDown(panel->whatP, False);
WMSetPopUpButtonText(panel->whatP, _("Select action"));
WMAddPopUpButtonItem(panel->whatP, _("Abort and leave a core file"));
WMAddPopUpButtonItem(panel->whatP, _("Restart Window Maker"));
WMAddPopUpButtonItem(panel->whatP, _("Start alternate window manager"));
WMSetPopUpButtonAction(panel->whatP, setAction, panel);
WMSetPopUpButtonSelectedItem(panel->whatP, WMRestart);
panel->action = WMRestart;
WMMapSubwidgets(panel->whatF);
panel->okB = WMCreateCommandButton(panel->win);
WMResizeWidget(panel->okB, 80, 26);
WMMoveWidget(panel->okB, 205, 309);
WMSetButtonText(panel->okB, _("OK"));
WMSetButtonImage(panel->okB, WMGetSystemPixmap(scr, WSIReturnArrow));
WMSetButtonAltImage(panel->okB, WMGetSystemPixmap(scr, WSIHighlightedReturnArrow));
WMSetButtonImagePosition(panel->okB, WIPRight);
WMSetButtonAction(panel->okB, buttonCallback, panel);
panel->done = 0;
WMCreateEventHandler(WMWidgetView(panel->win), KeyPressMask,
handleKeyPress, panel);
WMRealizeWidget(panel->win);
WMMapSubwidgets(panel->win);
WMMapWidget(panel->win);
XSetInputFocus(newdpy, WMWidgetXID(panel->win), RevertToParent, CurrentTime);
while (!panel->done) {
XEvent event;
WMNextEvent(newdpy, &event);
WMHandleEvent(&event);
}
action = panel->action;
WMUnmapWidget(panel->win);
WMDestroyWidget(panel->win);
free(panel);
XCloseDisplay(newdpy);
return action;
}
static int
catchXError(Display *dpy, XErrorEvent *error)
{
@@ -241,6 +494,7 @@ handleSig(int sig)
static int already_crashed = 0;
int dumpcore = 0;
#ifndef NO_EMERGENCY_AUTORESTART
int crashAction;
char *argv[2];
argv[1] = NULL;
@@ -259,7 +513,6 @@ handleSig(int sig)
#endif
WCHANGE_STATE(WSTATE_NEED_RESTART);
/* setup idle handler, so that this will be handled when
* the select() is returned becaused of the signal, even if
* there are no X events in the queue */
@@ -290,31 +543,41 @@ handleSig(int sig)
wfatal(_("got signal %i\n"), sig);
#endif
/* Setting the signal behaviour back to default and then reraising the
* signal is a cleaner way to make program exit and core dump than calling
* abort(), since it correctly returns from the signal handler and sets
* the flags accordingly. -Dan
*/
if (sig==SIGSEGV || sig==SIGFPE || sig==SIGBUS || sig==SIGILL
|| sig==SIGABRT) {
if (already_crashed) {
wfatal(_("crashed while trying to do some post-crash cleanup. Aborting immediatelly."));
#ifndef NO_EMERGENCY_AUTORESTART
exit(1);
#else
abort();
#endif
signal(sig, SIG_DFL);
raise(sig);
return;
}
already_crashed = 1;
dumpcore = 1;
wfatal(_("a fatal error has occured, probably due to a bug. "
"Please fill the included BUGFORM and report it."));
#ifndef NO_EMERGENCY_AUTORESTART
/* restart another window manager so that the X session doesn't
* go to space */
crashAction = showCrashPanel(sig);
wwarning(_("trying to start alternative window manager..."));
if (dpy)
XCloseDisplay(dpy);
dpy = NULL;
if (crashAction == WMAbort) {
signal(sig, SIG_DFL);
raise(sig);
return;
}
if (crashAction == WMRestart) {
/* we try to restart Window Maker */
wwarning(_("trying to restart Window Maker..."));
execvp(Arguments[0], Arguments);
wwarning(_("we failed to restart Window Maker."));
/* fallback to alternate window manager then */
}
wwarning(_("trying to start alternate window manager..."));
argv[0] = FALLBACK_WINDOWMANAGER;
execvp(FALLBACK_WINDOWMANAGER, argv);
@@ -323,8 +586,18 @@ handleSig(int sig)
execvp("fvwm", argv);
argv[0] = "twm";
execvp("twm", argv);
execvp("twm", argv);
wfatal(_("failed to start alternate window manager. Aborting."));
#else
wfatal(_("a fatal error has occured, probably due to a bug. "
"Please fill the included BUGFORM and report it."));
#endif /* !NO_EMERGENCY_AUTORESTART */
signal(sig, SIG_DFL);
raise(sig);
return;
}
wAbort(dumpcore);
@@ -702,9 +975,7 @@ StartUp(Bool defaultScreenOnly)
sigaction(SIGSEGV, &sig_action, NULL);
sigaction(SIGBUS, &sig_action, NULL);
sigaction(SIGFPE, &sig_action, NULL);
#ifndef NO_EMERGENCY_AUTORESTART
sigaction(SIGABRT, &sig_action, NULL);
#endif
/* Here we set SA_RESTART for safety, because SIGUSR1 may not be handled
* immediately.
@@ -722,6 +993,17 @@ StartUp(Bool defaultScreenOnly)
sig_action.sa_flags = SA_NOCLDSTOP|SA_RESTART;
sigaction(SIGCHLD, &sig_action, NULL);
/* Now we unblock all signals, that may have been blocked by the parent
* who exec()-ed us. This can happen for example if Window Maker crashes
* and restarts itself or another window manager from the signal handler.
* In this case, the new proccess inherits the blocked signal mask and
* will no longer react to that signal, until unblocked.
* This is because the signal handler of the proccess who crashed (parent)
* didn't return, and the signal remained blocked. -Dan
*/
sigfillset(&sig_action.sa_mask);
sigprocmask(SIG_UNBLOCK, &sig_action.sa_mask, NULL);
/* handle X shutdowns a such */
XSetIOErrorHandler(handleXIO);
@@ -761,7 +1043,6 @@ StartUp(Bool defaultScreenOnly)
XSetErrorHandler((XErrorHandler)catchXError);
/* Sound init */
#ifdef SHAPE
/* ignore j */
wShapeSupported = XShapeQueryExtension(dpy, &wShapeEventBase, &j);
@@ -781,7 +1062,7 @@ StartUp(Bool defaultScreenOnly)
if (defaultScreenOnly || max==1) {
wScreen[wScreenCount] = wScreenInit(DefaultScreen(dpy));
if (!wScreen[wScreenCount]) {
wfatal(_("it seems that there already is a window manager running"));
wfatal(_("it seems that there is already a window manager running"));
Exit(1);
}
} else {