Better, cleaner error handling.

This commit is contained in:
Kris Maglione 2008-10-11 19:05:24 -04:00
parent f4f492efd8
commit 812f07a6a1
6 changed files with 110 additions and 81 deletions

View File

@ -159,7 +159,6 @@ client_create(XWindow w, XWindowAttributes *wa) {
p.x = def.border;
p.y = labelh(def.font);
reparentwindow(&c->w, c->framewin, p);
group_init(c);
@ -172,6 +171,20 @@ client_create(XWindow w, XWindowAttributes *wa) {
break;
}
/*
* It's actually possible for a window to be destroyed
* before we get a chance to reparant it. Check for that
* now, because otherwise we'll wind up mapping an empty
* frame.
*/
traperrors(true);
reparentwindow(&c->w, c->framewin, p);
if(traperrors(false)) {
client_destroy(c);
return nil;
}
ewmh_initclient(c);
event("CreateClient %C\n", c);
@ -181,7 +194,7 @@ client_create(XWindow w, XWindowAttributes *wa) {
void
client_manage(Client *c) {
Client *trans;
Client *leader;
Frame *f;
char *tags;
@ -192,14 +205,14 @@ client_manage(Client *c) {
tags = getprop_string(&c->w, "_WMII_TAGS");
trans = win2client(c->trans);
if(trans == nil && c->group)
trans = group_leader(c->group);
leader = win2client(c->trans);
if(leader == nil && c->group)
leader = group_leader(c->group);
if(tags && (!trans || starting))
if(tags && (!leader || leader == c || starting))
utflcpy(c->tags, tags, sizeof c->tags);
else if(trans)
utflcpy(c->tags, trans->tags, sizeof c->tags);
else if(leader)
utflcpy(c->tags, leader->tags, sizeof c->tags);
free(tags);
if(!c->tags[0])
@ -231,15 +244,8 @@ client_manage(Client *c) {
}
}
static int /* Temporary Xlib error handler */
ignoreerrors(Display *d, XErrorEvent *e) {
USED(d, e);
return 0;
}
void
client_destroy(Client *c) {
int (*handler)(Display*, XErrorEvent*);
Rectangle r;
char *none;
Client **tc;
@ -261,8 +267,9 @@ client_destroy(Client *c) {
hide = true;
XGrabServer(display);
/* In case the client is already destroyed. */
handler = XSetErrorHandler(ignoreerrors);
traperrors(true);
sethandler(&c->w, nil);
if(hide)
@ -270,8 +277,7 @@ client_destroy(Client *c) {
else
reparentwindow(&c->w, &scr.root, r.min);
sync();
XSetErrorHandler(handler);
traperrors(false);
XUngrabServer(display);
none = nil;

View File

@ -235,10 +235,15 @@ static void
trampoline(int fn, Frame *f) {
while(fn > 0) {
resizing = fn != TFloat;
view_update(f->view);
warppointer(grabboxcenter(f));
//f->collapsed = false;
fn = tramp[fn](f);
}
ungrabpointer();
resizing = false;
view_update(f->view);
}
void
@ -255,17 +260,11 @@ mouse_movegrabbox(Client *c, bool grabmod) {
y = (float)p.y / Dy(f->r);
}
resizing = true;
view_update(f->view);
warppointer(grabboxcenter(f));
if(f->area->floating)
trampoline(TFloat, f);
else
trampoline(THCol, f);
resizing = false;
view_update(f->view);
if(grabmod)
warppointer(addpt(f->r.min, Pt(x * Dx(f->r),
y * Dy(f->r))));

View File

@ -17,10 +17,8 @@
static const char
version[] = "wmii-"VERSION", ©2008 Kris Maglione\n";
static int (*xlib_errorhandler) (Display*, XErrorEvent*);
static char* address;
static char* ns_path;
static bool check_other_wm;
static int sleeperfd;
static int sock;
static int exitsignal;
@ -136,6 +134,23 @@ init_cursors(void) {
XFreePixmap(display, pix);
}
/*
* There's no way to check accesses to destroyed windows, thus
* those cases are ignored (especially on UnmapNotifies).
* Other types of errors call Xlib's default error handler, which
* calls exit().
*/
ErrorCode ignored_xerrors[] = {
{ 0, BadWindow },
{ X_SetInputFocus, BadMatch },
{ X_PolyText8, BadDrawable },
{ X_PolyFillRectangle, BadDrawable },
{ X_PolySegment, BadDrawable },
{ X_ConfigureWindow, BadMatch },
{ X_GrabKey, BadAccess },
{ X_GetAtomName, BadAtom },
};
void
init_screen(WMScreen *screen) {
@ -157,51 +172,6 @@ cleanup(void) {
close(sleeperfd);
}
/*
* There's no way to check accesses to destroyed windows, thus
* those cases are ignored (especially on UnmapNotifies).
* Other types of errors call Xlib's default error handler, which
* calls exit().
*/
static int
errorhandler(Display *dpy, XErrorEvent *error) {
static struct {
uchar rcode, ecode;
} itab[] = {
{ 0, BadWindow },
{ X_SetInputFocus, BadMatch },
{ X_PolyText8, BadDrawable },
{ X_PolyFillRectangle, BadDrawable },
{ X_PolySegment, BadDrawable },
{ X_ConfigureWindow, BadMatch },
{ X_GrabKey, BadAccess },
{ X_GetAtomName, BadAtom },
};
static int dead;
int i;
USED(dpy);
if(check_other_wm)
fatal("another window manager is already running");
for(i = 0; i < nelem(itab); i++)
if((itab[i].rcode == 0 || itab[i].rcode == error->request_code)
&& (itab[i].ecode == 0 || itab[i].ecode == error->error_code))
return 0;
fprint(2, "%s: fatal error: Xrequest code=%d, Xerror code=%d\n",
argv0, error->request_code, error->error_code);
/* Try to cleanup, but only try once, in case we're called recursively. */
USED(dead);
#ifdef notdef
if(!dead++)
cleanup();
#endif
return xlib_errorhandler(display, error); /* calls exit() */
}
static void
cleanup_handler(int signal) {
sa.sa_handler = SIG_DFL;
@ -338,14 +308,12 @@ extern int fmtevent(Fmt*);
initdisplay();
xlib_errorhandler = XSetErrorHandler(errorhandler);
check_other_wm = true;
traperrors(true);
selectinput(&scr.root, SubstructureRedirectMask
| EnterWindowMask);
sync();
check_other_wm = false;
if(traperrors(false))
fatal("another window manager is already running");
passwd = getpwuid(getuid());
user = estrdup(passwd->pw_name);

View File

@ -252,10 +252,11 @@ view_update(View *v) {
for(c=client; c; c=c->next) {
f = c->sel;
if(f && f->view == v
&& !(f->area && f->area->max && f->area->floating && f->area != v->sel))
client_resize(c, f->r);
else {
if((f && f->view == v)
&& (f->area == v->sel || !(f->area && f->area->max && f->area->floating))) {
if(f->area)
client_resize(c, f->r);
}else {
unmap_frame(c);
client_unmap(c, IconicState);
}
@ -304,8 +305,11 @@ view_attach(View *v, Frame *f) {
c = f->client;
oldsel = nil;
oldsel = v->oldsel;
a = v->sel;
print("view: %s\n", v->name);
print("client: %C\n", c);
print("< sel: %a\n", v->sel);
if(client_floats_p(c)) {
if(v->sel != v->area)
oldsel = v->sel;
@ -323,6 +327,7 @@ view_attach(View *v, Frame *f) {
else if(starting || c->sel && c->sel->area && !c->sel->area->floating)
a = v->area->next;
}
print("< sel: %a oldsel: %a\n", v->sel, oldsel);
area_attach(a, f);
/* TODO: Decide whether to focus this frame */
@ -341,6 +346,7 @@ view_attach(View *v, Frame *f) {
if(oldsel)
v->oldsel = oldsel;
print("< sel: %a oldsel: %a\n", v->sel, oldsel);
if(c->sel == nil)
c->sel = f;

View File

@ -27,6 +27,9 @@ static Map atommap;
static MapEnt* wbucket[137];
static MapEnt* abucket[137];
static int errorhandler(Display*, XErrorEvent*);
static int (*xlib_errorhandler) (Display*, XErrorEvent*);
/* Rectangles/Points */
XRectangle
@ -185,6 +188,46 @@ initdisplay(void) {
fmtinstall('R', Rfmt);
fmtinstall('P', Pfmt);
fmtinstall('W', Wfmt);
xlib_errorhandler = XSetErrorHandler(errorhandler);
}
/* Error handling */
ErrorCode ignored_xerrors[];
static bool _trap_errors;
static long nerrors;
static int
errorhandler(Display *dpy, XErrorEvent *error) {
ErrorCode *e;
USED(dpy);
if(_trap_errors)
nerrors++;
e = ignored_xerrors;
if(e)
for(; e->rcode || e->ecode; e++)
if((e->rcode == 0 || e->rcode == error->request_code)
&& (e->ecode == 0 || e->ecode == error->error_code))
return 0;
fprint(2, "%s: fatal error: Xrequest code=%d, Xerror code=%d\n",
argv0, error->request_code, error->error_code);
return xlib_errorhandler(display, error); /* calls exit() */
}
int
traperrors(bool enable) {
sync();
_trap_errors = enable;
if (enable)
nerrors = 0;
return nerrors;
}
/* Images */

View File

@ -48,6 +48,7 @@ struct Rectangle {
};
typedef struct CTuple CTuple;
typedef struct ErrorCode ErrorCode;
typedef struct Ewmh Ewmh;
typedef struct Font Font;
typedef struct Handlers Handlers;
@ -63,6 +64,11 @@ struct CTuple {
char colstr[24]; /* #RRGGBB #RRGGBB #RRGGBB */
};
struct ErrorCode {
uchar rcode;
uchar ecode;
};
struct Ewmh {
long type;
long ping;
@ -234,6 +240,7 @@ Point subpt(Point, Point);
void sync(void);
uint textwidth(Font*, char*);
uint textwidth_l(Font*, char*, uint len);
int traperrors(bool);
Point translate(Window*, Window*, Point);
void ungrabpointer(void);
int unmapwin(Window*);