wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

commit 812f07a6a145332b069ae2883c3dea3e01249b14
parent f4f492efd89c2a19b3337a9c9ebd2b073008e1de
Author: Kris Maglione <jg@suckless.org>
Date:   Sat, 11 Oct 2008 19:05:24 -0400

Better, cleaner error handling.

Diffstat:
cmd/wmii/client.c | 42++++++++++++++++++++++++------------------
cmd/wmii/layout.c | 11+++++------
cmd/wmii/main.c | 72++++++++++++++++++++----------------------------------------------------
cmd/wmii/view.c | 16+++++++++++-----
cmd/wmii/x11.c | 43+++++++++++++++++++++++++++++++++++++++++++
include/x11.h | 7+++++++
6 files changed, 110 insertions(+), 81 deletions(-)

diff --git a/cmd/wmii/client.c b/cmd/wmii/client.c @@ -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; diff --git a/cmd/wmii/layout.c b/cmd/wmii/layout.c @@ -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)))); diff --git a/cmd/wmii/main.c b/cmd/wmii/main.c @@ -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); diff --git a/cmd/wmii/view.c b/cmd/wmii/view.c @@ -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; diff --git a/cmd/wmii/x11.c b/cmd/wmii/x11.c @@ -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 */ diff --git a/include/x11.h b/include/x11.h @@ -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*);