wmii

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

commit e820f419493a49c0e86a87ebed0bb34a17686cbf
parent 079473c859ac4abba90458916a04b221bbc33f20
Author: Kris Maglione <jg@suckless.org>
Date:   Sat, 26 Jan 2008 21:13:42 -0500

Cleanup frame sizing and fix some long-standing bugs with borderless/titleless clients.

Diffstat:
cmd/util.c | 10++++++++--
cmd/wmii/bar.c | 10++++++----
cmd/wmii/client.c | 44+++++++++++++++++++++++---------------------
cmd/wmii/column.c | 5+++++
cmd/wmii/fns.h | 4++--
cmd/wmii/frame.c | 345+++++++++++++++++++++++++++++++++++++++----------------------------------------
cmd/wmii/main.c | 1-
cmd/wmii/x11.c | 32++++++++++++++++++++++++++++----
include/util.h | 6+++---
include/x11.h | 2++
mk/dir.mk | 6+++---
mk/hdr.mk | 4+++-
mk/many.mk | 1+
mk/one.mk | 1+
14 files changed, 254 insertions(+), 217 deletions(-)

diff --git a/cmd/util.c b/cmd/util.c @@ -79,9 +79,15 @@ sxprint(const char *fmt, ...) { } void -_die(char *file, int line, char *msg) { +_die(char *file, int line, char *msg, ...) { + va_list ap; + + va_start(ap, msg); fprint(2, "%s: dieing at %s:%d: %s\n", - argv0, file, line, msg); + argv0, file, line, + vsxprint(msg, ap)); + va_end(ap); + kill(getpid(), SIGABRT); abort(); /* Adds too many frames: * _die() diff --git a/cmd/wmii/bar.c b/cmd/wmii/bar.c @@ -122,7 +122,7 @@ bar_draw(WMScreen *s) { float shrink; largest = nil; - tw = width = 0; + width = 0; foreach_bar(s, b) { b->r.min = ZP; b->r.max.y = Dy(s->brect); @@ -141,13 +141,15 @@ bar_draw(WMScreen *s) { *pb = b; } SET(shrink); + tw = 0; for(tb=largest; tb; tb=tb->smaller) { width -= Dx(tb->r); tw += Dx(tb->r); shrink = (Dx(s->brect) - width) / (float)tw; - if(tb->smaller) - if(Dx(tb->r) * shrink >= Dx(tb->smaller->r)) - break; + if(tb->smaller && Dx(tb->r) * shrink < Dx(tb->smaller->r)) + continue; + if(width + (int)(tw * shrink) <= Dx(s->brect)) + break; } if(tb) for(b=largest; b != tb->smaller; b=b->smaller) diff --git a/cmd/wmii/client.c b/cmd/wmii/client.c @@ -180,7 +180,10 @@ client_manage(Client *c) { /* Maybe not the best idea... */ if(!c->trans || !c->tags[0]) apply_rules(c); - apply_tags(c, c->tags); + if(c->tags[0]) + apply_tags(c, c->tags); + else + apply_tags(c, "sel"); if(!starting) view_update_all(); @@ -310,28 +313,30 @@ clientname(Client *c) { Rectangle client_grav(Client *c, Rectangle rd) { - Rectangle r; + Rectangle r, cr; Point sp; WinHints *h; h = c->w.hints; - sp = Pt(def.border, labelh(def.font)); if(eqrect(rd, ZR)) { if(c->sel) { r = c->sel->floatr; }else - r = frame_client2rect(nil, c->r); - r = gravitate(r, c->r, h->grav); - if(h->gravstatic) - r = rectaddpt(r, sp); - return frame_rect2client(nil, r); + r = frame_client2rect(c, c->r, true); + cr = frame_rect2client(c, r, true); + sp = subpt(cr.min, r.min); + r = gravitate(r, cr, h->grav); + if(!h->gravstatic) + r = rectsubpt(r, sp); + return frame_rect2client(c, r, true); }else { - r = frame_client2rect(nil, rd); + r = frame_client2rect(c, rd, true); + sp = subpt(rd.min, r.min); r = gravitate(rd, r, h->grav); - if(h->gravstatic) - r = rectsubpt(r, sp); - return frame_client2rect(nil, r); + if(!h->gravstatic) + r = rectaddpt(r, sp); + return frame_client2rect(c, r, true); } } @@ -364,9 +369,9 @@ frame_hints(Frame *f, Rectangle r, Align sticky) { return r; or = r; - r = frame_rect2client(f, r); + r = frame_rect2client(c, r, f->area->floating); r = sizehint(c->w.hints, r); - r = frame_client2rect(f, r); + r = frame_client2rect(c, r, f->area->floating); if(!f->area->floating) { /* Not allowed to grow */ @@ -381,7 +386,6 @@ frame_hints(Frame *f, Rectangle r, Align sticky) { p.x = Dx(or) - Dx(r); if((sticky&(North|South)) == South) p.y = Dy(or) - Dy(r); - return rectaddpt(r, p); } @@ -674,8 +678,9 @@ updatemwm(Client *c) { n = getprop_long(&c->w, "_MOTIF_WM_HINTS", "_MOTIF_WM_HINTS", 0L, (long**)&ret, 3L); + /* FIXME: Look over this. */ if(c->sel) - r = frame_rect2client(c->sel, c->sel->r); + r = frame_rect2client(c, c->sel->r, c->sel->area->floating); c->borderless = 0; c->titleless = 0; @@ -688,7 +693,7 @@ updatemwm(Client *c) { free(ret); if(c->sel) { - r = frame_client2rect(c->sel, r); + r = frame_client2rect(c, r, c->sel->area->floating); client_resize(c, r); frame_draw(c->sel); } @@ -775,8 +780,7 @@ configreq_event(Window *w, XConfigureRequestEvent *e) { client_resize(c, r); sync(); flushenterevents(); - } - else { + }else { c->sel->floatr = r; client_configure(c); } @@ -1075,7 +1079,5 @@ apply_rules(Client *c) { apply_tags(c, r->value); break; } - if(c->tags[0] == '\0') - apply_tags(c, "sel"); } diff --git a/cmd/wmii/column.c b/cmd/wmii/column.c @@ -248,6 +248,11 @@ column_scale(Area *a) { } } + if(surplus < 0) { + print("Badness: surplus = %d\n", surplus); + surplus = 0; + } + yoff = a->r.min.y; i = nuncol; for(f=a->frame; f; f=f->anext) { diff --git a/cmd/wmii/fns.h b/cmd/wmii/fns.h @@ -124,9 +124,9 @@ void frame_swap(Frame*, Frame*); int ingrabbox_p(Frame*, int x, int y); void move_focus(Frame*, Frame*); Rectangle constrain(Rectangle); -Rectangle frame_client2rect(Frame*, Rectangle); +Rectangle frame_client2rect(Client*, Rectangle, bool); +Rectangle frame_rect2client(Client*, Rectangle, bool); Rectangle frame_hints(Frame*, Rectangle, Align); -Rectangle frame_rect2client(Frame*, Rectangle); /* fs.c */ void fs_attach(Ixp9Req*); diff --git a/cmd/wmii/frame.c b/cmd/wmii/frame.c @@ -29,9 +29,8 @@ frame_create(Client *c, View *v) { if(c->sel) { f->floatr = c->sel->floatr; f->r = c->sel->r; - } - else{ - f->r = frame_client2rect(f, client_grav(c, ZR)); + }else{ + f->r = frame_client2rect(c, client_grav(c, ZR), true); f->floatr = f->r; c->sel = f; } @@ -243,58 +242,63 @@ Handlers framehandler = { /* These must die!!! */ Rectangle -frame_rect2client(Frame *f, Rectangle r) { - if(f == nil || f->area == nil || f->area->floating) { - r.max.x -= def.border * 2; - r.max.y -= frame_delta_h(); - if(f) { - if(f->client->borderless) { - r.max.x += 2 * def.border; - r.max.y += def.border; - } - if(f->client->titleless) - r.max.y += labelh(def.font); - } +frame_rect2client(Client *c, Rectangle r, bool floating) { + + if(c->fullscreen) + return r; + + if(!floating) { + r.min.x += 1; + r.min.y += labelh(def.font); + r.max.x -= 1; + r.max.y -= 1; }else { - r.max.x -= 2; - r.max.y -= labelh(def.font) + 1; + if(!c->borderless) { + r.min.x += def.border; + r.max.x -= def.border; + r.max.y -= def.border; + } + if(!c->titleless) + r.min.y += labelh(def.font); } - r.max.x = max(r.min.x+1, r.max.x); - r.max.y = max(r.min.y+1, r.max.y); + r.max.x = max(r.max.x, r.min.x+1); + r.max.y = max(r.max.y, r.min.y+1); return r; } Rectangle -frame_client2rect(Frame *f, Rectangle r) { - if(f == nil || f->area == nil || f->area->floating) { - r.max.x += def.border * 2; - r.max.y += frame_delta_h(); - if(f) { - if(f->client->borderless) { - r.max.x -= 2 * def.border; - r.max.y -= def.border; - } - if(f->client->titleless) - r.max.y -= labelh(def.font); - } +frame_client2rect(Client *c, Rectangle r, bool floating) { + + if(c->fullscreen) + return r; + + if(!floating) { + r.min.x -= 1; + r.min.y -= labelh(def.font); + r.max.x += 1; + r.max.y += 1; }else { - r.max.x += 2; - r.max.y += labelh(def.font) + 1; + if(!c->borderless) { + r.min.x -= def.border; + r.max.x += def.border; + r.max.y += def.border; + } + if(!c->titleless) + r.min.y -= labelh(def.font); } return r; } -/* FIXME: This is getting entirely too long! */ void frame_resize(Frame *f, Rectangle r) { Client *c; - Rectangle cr; - Point pt; - Align stickycorner; + Rectangle fr, cr; int collapsed; - c = f->client; + if(Dx(r) <= 0 || Dy(r) <= 0) + die("Frame rect: %R\n", r); + c = f->client; if(c->fullscreen) { f->crect = screen->r; f->r = screen->r; @@ -304,56 +308,148 @@ frame_resize(Frame *f, Rectangle r) { if(f->area->floating) f->collapsed = false; - stickycorner = get_sticky(f->r, r); - f->crect = frame_hints(f, r, stickycorner); - - if(Dx(r) <= 0 || Dy(r) <= 0) - fprint(2, "Badness: Frame rect: %R\n", r); - - if(f->area->floating) - f->r = f->crect; - else - f->r = r; - - cr = frame_rect2client(f, f->crect); - cr = rectsubpt(cr, cr.min); + fr = frame_hints(f, r, get_sticky(f->r, r)); + if(f->area->floating && !c->strut) + fr = constrain(fr); + /* Collapse managed frames which are too small */ collapsed = f->collapsed; - if(!f->area->floating && f->area->mode == Coldefault) { + f->collapsed = false; if(Dy(f->r) < 2 * labelh(def.font)) - f->collapsed = True; - else - f->collapsed = False; + f->collapsed = true; } - - if(Dx(cr) < labelh(def.font)) - f->r.max.x = f->r.min.x + frame_delta_h(); - - if(f->collapsed) { - f->r.max.y = f->r.min.y + labelh(def.font); - cr = f->r; - } - if(collapsed != f->collapsed) ewmh_updatestate(c); - pt = ZP; - if(!f->client->borderless || !f->area->floating) - pt.y += 1; - if(!f->client->titleless || !f->area->floating) - pt.y += labelh(def.font) - 1; + fr.max.x = max(fr.max.x, fr.min.x + 2*labelh(def.font)); + if(f->collapsed) + fr.max.y = fr.min.y + labelh(def.font); - if(f->area->floating && !f->client->strut) - f->r = constrain(f->r); + cr = frame_rect2client(c, fr, f->area->floating); + if(f->area->floating) + f->r = fr; + else { + cr.min.x += ((Dx(fr) - Dx(cr)) - 2 * (cr.min.x - fr.min.x)) + / 2; + f->r = r; + } + f->crect = rectsubpt(cr, f->r.min); if(f->area->floating) f->floatr = f->r; else f->colr = f->r; +} + +void +frame_draw(Frame *f) { + Rectangle r, fr; + Client *c; + CTuple *col; + Frame *tf; + uint w; + + if(f->view != screen->sel) + return; + if(f->area == nil) /* Blech. */ + return; + + c = f->client; + + if(c == screen->focus + || c == selclient()) + col = &def.focuscolor; + else + col = &def.normcolor; + if(!f->area->floating && f->area->mode == Colmax) + for(tf = f->area->frame; tf; tf=tf->anext) + if(tf->client == screen->focus) { + col = &def.focuscolor; + break; + } + fr = c->framewin->r; + fr = rectsubpt(fr, fr.min); + + /* background */ + r = fr; + fill(screen->ibuf, r, col->bg); + border(screen->ibuf, r, 1, col->border); + + r.max.y = r.min.y + labelh(def.font); + border(screen->ibuf, r, 1, col->border); + + f->titlebar = insetrect(r, 3); + f->titlebar.max.y += 3; + + /* Odd state of focus. */ + if(c != selclient() && col == &def.focuscolor) + border(screen->ibuf, insetrect(r, 1), + 1, def.normcolor.bg); + + /* grabbox */ + r.min = Pt(2, 2); + r.max.x = r.min.x + def.font->height - 3; + r.max.y -= 2; + f->grabbox = r; + + if(c->urgent) + fill(screen->ibuf, r, col->fg); + border(screen->ibuf, r, 1, col->border); + + /* Odd state of focus. */ + if(c != screen->focus && col == &def.focuscolor) + border(screen->ibuf, insetrect(r, -1), + 1, def.normcolor.bg); + if(c->borderless && c->titleless && c == selclient()) + setborder(c->framewin, def.border, def.focuscolor.border); + else + setborder(c->framewin, 0, 0); + + /* Label */ + r.min.x = r.max.x; + r.max.x = fr.max.x; + r.min.y = 0; + r.max.y = labelh(def.font); + if(c->floating) + r.max.x -= Dx(f->grabbox); + w = drawstring(screen->ibuf, def.font, r, West, + c->name, col->fg); + + if(f->area->floating) { + r.min.x = r.min.x + w + 10; + r.max.x = f->titlebar.max.x + 1; + r.min.y = f->grabbox.min.y; + r.max.y = f->grabbox.max.y; + border(screen->ibuf, r, 1, col->border); + } + + /* Border increment gaps... */ + r.min.y = f->crect.min.y; + r.min.x = max(1, f->crect.min.x - 1); + r.max.x = min(fr.max.x - 1, f->crect.max.x + 1); + r.max.y = min(fr.max.y - 1, f->crect.max.y + 1); + border(screen->ibuf, r, 1, col->border); - pt.x = (Dx(f->r) - Dx(cr)) / 2; - f->crect = rectaddpt(cr, pt); + /* Why? Because some non-ICCCM-compliant apps feel the need to + * change the background properties of all of their ancestor windows + * in order to implement pseudo-transparency. + * What's more, the designers of X11 felt that it would be unfair to + * implementers to make it possible to detect, or forbid, such changes. + */ + XSetWindowBackgroundPixmap(display, c->framewin->w, None); + + copyimage(c->framewin, fr, screen->ibuf, ZP); + sync(); +} + +void +frame_draw_all(void) { + Client *c; + + for(c=client; c; c=c->next) + if(c->sel && c->sel->view == screen->sel) + frame_draw(c->sel); } void @@ -450,109 +546,6 @@ frame_delta_h(void) { return def.border + labelh(def.font); } -void -frame_draw(Frame *f) { - Rectangle r, fr; - CTuple *col; - Frame *tf; - uint w; - - if(f->view != screen->sel) - return; - if(f->area == nil) /* Blech. */ - return; - - if(f->client == screen->focus - || f->client == selclient()) - col = &def.focuscolor; - else - col = &def.normcolor; - if(!f->area->floating && f->area->mode == Colmax) - for(tf = f->area->frame; tf; tf=tf->anext) - if(tf->client == screen->focus) { - col = &def.focuscolor; - break; - } - fr = f->client->framewin->r; - fr = rectsubpt(fr, fr.min); - - /* background */ - r = fr; - fill(screen->ibuf, r, col->bg); - border(screen->ibuf, r, 1, col->border); - - r.max.y = r.min.y + labelh(def.font); - border(screen->ibuf, r, 1, col->border); - - f->titlebar = insetrect(r, 3); - f->titlebar.max.y += 3; - - /* Odd state of focus. */ - if(f->client != selclient() && col == &def.focuscolor) - border(screen->ibuf, insetrect(r, 1), - 1, def.normcolor.bg); - - /* grabbox */ - r.min = Pt(2, 2); - r.max.x = r.min.x + def.font->height - 3; - r.max.y -= 2; - f->grabbox = r; - - if(f->client->urgent) - fill(screen->ibuf, r, col->fg); - border(screen->ibuf, r, 1, col->border); - - /* Odd state of focus. */ - if(f->client != screen->focus && col == &def.focuscolor) - border(screen->ibuf, insetrect(r, -1), - 1, def.normcolor.bg); - - /* Label */ - r.min.x = r.max.x; - r.max.x = fr.max.x; - r.min.y = 0; - r.max.y = labelh(def.font); - if(f->client->floating) - r.max.x -= Dx(f->grabbox); - w = drawstring(screen->ibuf, def.font, r, West, - f->client->name, col->fg); - - if(f->area->floating) { - r.min.x = r.min.x + w + 10; - r.max.x = f->titlebar.max.x + 1; - r.min.y = f->grabbox.min.y; - r.max.y = f->grabbox.max.y; - border(screen->ibuf, r, 1, col->border); - } - - /* Border increment gaps... */ - r.min.y = f->crect.min.y; - r.min.x = max(1, f->crect.min.x - 1); - r.max.x = min(fr.max.x - 1, f->crect.max.x + 1); - r.max.y = min(fr.max.y - 1, f->crect.max.y + 1); - border(screen->ibuf, r, 1, col->border); - - /* Why? Because some non-ICCCM-compliant apps feel the need to - * change the background properties of all of their ancestor windows - * in order to implement pseudo-transparency. - * What's more, the designers of X11 felt that it would be unfair to - * implementers to make it possible to detect, or forbid, such changes. - */ - XSetWindowBackgroundPixmap(display, f->client->framewin->w, None); - - copyimage(f->client->framewin, fr, screen->ibuf, ZP); - sync(); -} - -void -frame_draw_all(void) { - Client *c; - - for(c=client; c; c=c->next) - if(c->sel && c->sel->view == screen->sel) - frame_draw(c->sel); -} - Rectangle constrain(Rectangle r) { Rectangle sr; diff --git a/cmd/wmii/main.c b/cmd/wmii/main.c @@ -241,7 +241,6 @@ errorhandler(Display *dpy, XErrorEvent *error) { /* Try to cleanup, but only try once, in case we're called recursively. */ if(!dead++) cleanup(); - abort(); return xlib_errorhandler(display, error); /* calls exit() */ } diff --git a/cmd/wmii/x11.c b/cmd/wmii/x11.c @@ -243,6 +243,7 @@ window(XWindow xw) { void reparentwindow(Window *w, Window *par, Point p) { + assert(w->type == WWindow); XReparentWindow(display, w->w, par->w, p.x, p.y); w->parent = par; w->r = rectsubpt(w->r, w->r.min); @@ -266,11 +267,31 @@ setwinattr(Window *w, WinAttr *wa, int valmask) { } void +setborder(Window *w, int width, long pixel) { + Rectangle r; + + assert(w->type == WWindow); + if(width) + XSetWindowBorder(display, w->w, pixel); + if(w->border != width) { + w->border = width; + XSetWindowBorderWidth(display, w->w, width); + /* FIXME: Kludge */ + r = w->r; + w->r = ZR; + reshapewin(w, r); + } +} + +void reshapewin(Window *w, Rectangle r) { assert(w->type == WWindow); - if(!eqrect(r, w->r)) + assert(Dx(r) > 0 && Dy(r) > 0); /* Rather than an X error. */ + if(!eqrect(r, w->r)) { + w->r = r; + r = rectsubpt(r, Pt(w->border, w->border)); XMoveResizeWindow(display, w->w, r.min.x, r.min.y, Dx(r), Dy(r)); - w->r = r; + } } void @@ -278,13 +299,13 @@ movewin(Window *w, Point pt) { Rectangle r; assert(w->type == WWindow); - r = rectsubpt(w->r, w->r.min); - r = rectaddpt(r, pt); + r = rectsetorigin(w->r, pt); reshapewin(w, r); } int mapwin(Window *w) { + assert(w->type == WWindow); if(!w->mapped) { XMapWindow(display, w->w); w->mapped = 1; @@ -295,6 +316,7 @@ mapwin(Window *w) { int unmapwin(Window *w) { + assert(w->type == WWindow); if(w->mapped) { XUnmapWindow(display, w->w); w->mapped = 0; @@ -306,11 +328,13 @@ unmapwin(Window *w) { void raisewin(Window *w) { + assert(w->type == WWindow); XRaiseWindow(display, w->w); } void lowerwin(Window *w) { + assert(w->type == WWindow); XLowerWindow(display, w->w); } diff --git a/include/util.h b/include/util.h @@ -28,7 +28,7 @@ typedef long long vlong; #define strlcat wmii_strlcat /* util.c */ -void _die(char*, int, char*); +void _die(char*, int, char*, ...); void* emalloc(uint); void* emallocz(uint); void* erealloc(void*, uint); @@ -43,8 +43,8 @@ uint tokenize(char **, uint, char*, char); int utflcpy(char*, const char*, int); char* vsxprint(const char*, va_list); -#define die(x) \ - _die(__FILE__, __LINE__, x) +#define die(...) \ + _die(__FILE__, __LINE__, __VA_ARGS__) char *argv0; #undef ARGBEGIN diff --git a/include/x11.h b/include/x11.h @@ -115,6 +115,7 @@ struct Window { XID w; GC gc; Rectangle r; + int border; Window* parent; Window* next; Window* prev; @@ -218,6 +219,7 @@ void raisewin(Window*); void reparentwindow(Window*, Window*, Point); void reshapewin(Window*, Rectangle); void sendevent(Window*, bool propegate, long mask, XEvent*); +void setborder(Window*, int, long); void setfocus(Window*, int mode); void sethints(Window*); void setshapemask(Window *dst, Image *src, Point); diff --git a/mk/dir.mk b/mk/dir.mk @@ -1,10 +1,10 @@ -MKSUBDIR = targ=$@; \ +MKSUBDIR = targ=$@; targ=$${targ\#d}; \ for i in $$dirs; do \ if [ ! -d $$i ]; then \ echo Skipping nonexistent directory: $$i 1>&2; \ else \ - echo MAKE $${targ\#d} $(BASE)$$i/; \ - (cd $$i && $(MAKE) BASE="$(BASE)$$i/" $${targ\#d}) || exit $?; \ + echo MAKE $$targ $(BASE)$$i/; \ + (cd $$i && $(MAKE) BASE="$(BASE)$$i/" $$targ) || exit $?; \ fi; \ done diff --git a/mk/hdr.mk b/mk/hdr.mk @@ -21,7 +21,7 @@ all: .c.depend: echo MKDEP $< - $(MKDEP) $(CFLAGS) $< >>.depend + $(MKDEP) $(EXCFLAGS) $(CFLAGS) $< >>.depend .sh.depend .rc.depend .1.depend .awk.depend: : @@ -82,9 +82,11 @@ all: rm -f $(MAN)/man1/$< .O.clean: + echo CLEAN $$($(CLEANNAME) $(BASE)$<) rm -f $< || true 2>/dev/null rm -f $*.o || true 2>/dev/null .o.clean .o_pic.clean: + echo CLEAN $$($(CLEANNAME) $(BASE)$<) rm -f $< || true 2>/dev/null printinstall: diff --git a/mk/many.mk b/mk/many.mk @@ -13,6 +13,7 @@ printinstall: manyclean: for i in ${TARG:=.o} ${TARG:=.O} $(OFILES); do \ + echo CLEAN $$($(CLEANNAME) $(BASE)$$i); \ rm -f $$i; \ done 2>/dev/null || true diff --git a/mk/one.mk b/mk/one.mk @@ -14,6 +14,7 @@ printinstall: oneclean: for i in $(PROG) $(OFILES); do \ + echo CLEAN $$($(CLEANNAME) $(BASE)$$i); \ rm -f $$i; \ done 2>/dev/null || true