From 443c6cbe66f3b8634954d2e3fa0ce903d6d74287 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Sat, 9 Feb 2008 13:23:27 -0500 Subject: [PATCH] Fix column scaling a bit. --- cmd/wmii/_util.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++ cmd/wmii/area.c | 7 ++- cmd/wmii/client.c | 9 ++- cmd/wmii/column.c | 110 +++++++++++++++++++++++-------------- cmd/wmii/dat.h | 2 +- cmd/wmii/fns.h | 7 ++- cmd/wmii/frame.c | 9 ++- cmd/wmii/main.c | 32 ----------- 8 files changed, 230 insertions(+), 83 deletions(-) diff --git a/cmd/wmii/_util.c b/cmd/wmii/_util.c index adad8e34..aa3be49b 100644 --- a/cmd/wmii/_util.c +++ b/cmd/wmii/_util.c @@ -2,6 +2,10 @@ * See LICENSE file for license details. */ #include "dat.h" +#include +#include +#include +#include #include "fns.h" /* Blech. */ @@ -32,6 +36,139 @@ VECTOR(long, long, l) VECTOR(Rectangle, rect, r) VECTOR(void*, ptr, p) +int +doublefork(void) { + pid_t pid; + int status; + + switch(pid=fork()) { + case -1: + fatal("Can't fork(): %r"); + case 0: + switch(pid=fork()) { + case -1: + fatal("Can't fork(): %r"); + case 0: + return 0; + default: + exit(0); + } + default: + waitpid(pid, &status, 0); + return pid; + } + /* NOTREACHED */ +} + +void +closeexec(int fd) { + if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("can't set %d close on exec: %r", fd); +} + +int +spawn3(int fd[3], const char *file, char *argv[]) { + /* Some ideas from Russ Cox's libthread port. */ + int p[2]; + int pid; + int _errno; + + if(pipe(p) < 0) + return -1; + closeexec(p[1]); + + switch(pid = doublefork()) { + case 0: + dup2(fd[0], 0); + dup2(fd[1], 1); + dup2(fd[2], 2); + + execvp(file, argv); + write(p[1], &errno, sizeof _errno); + exit(1); + break; + default: + close(p[1]); + if(read(p[0], &_errno, sizeof _errno) == sizeof _errno) + pid = -1; + close(p[0]); + break; + case -1: /* can't happen */ + break; + } + + close(fd[0]); + /* These could fail if any of these was also a previous fd. */ + close(fd[1]); + close(fd[2]); + return pid; +} + +int +spawn3l(int fd[3], const char *file, ...) { + va_list ap; + char **argv; + int i, n; + + va_start(ap, file); + for(n=0; va_arg(ap, char*); n++) + ; + va_end(ap); + + argv = emalloc((n+1) * sizeof *argv); + va_start(ap, file); + for(i=0; i <= n; i++) + argv[i] = va_arg(ap, char*); + va_end(ap); + + return spawn3(fd, file, argv); +} + +void +backtrace(void) { + char *proc, *spid; + int fd[3], p[2], q[2]; + int pid, status, n; + + proc = sxprint("/proc/%d/file", getpid()); + spid = sxprint("%d", getpid()); + switch(pid = fork()) { + case -1: + return; + case 0: + break; + default: + waitpid(pid, &status, 0); + return; + } + + if(pipe(p) < 0 || pipe(q) < 0) + exit(0); + closeexec(p[1]); + closeexec(q[0]); + + fd[0] = p[0]; + fd[1] = q[1]; + fd[2] = open("/dev/null", O_WRONLY); + if(spawn3l(fd, "gdb", "gdb", "-batch", "-x", "/dev/fd/0", proc, spid, nil) < 0) + exit(1); + + fprint(p[1], "bt full\n"); + fprint(p[1], "detach\n"); + close(p[1]); + + /* Why? Because gdb freezes waiting for user input + * if its stdout is a tty. + */ + /* It'd be nice to make this a /debug file at some point, + * anyway. + */ + while((n = read(q[0], buffer, sizeof buffer)) > 0) + write(2, buffer, n); + exit(0); + +} + void reinit(Regex *r, char *regx) { diff --git a/cmd/wmii/area.c b/cmd/wmii/area.c index b248c5da..30a63013 100644 --- a/cmd/wmii/area.c +++ b/cmd/wmii/area.c @@ -191,8 +191,11 @@ area_attach(Area *a, Frame *f) { view_arrange(a->view); - if(a->frame) - assert(a->sel); + if(a->frame && a->sel == nil) { + fprint(2, "a->sel == nil\n"); + backtrace(); + a->sel = a->frame; + } } void diff --git a/cmd/wmii/client.c b/cmd/wmii/client.c index 34b5f219..d9abd376 100644 --- a/cmd/wmii/client.c +++ b/cmd/wmii/client.c @@ -263,6 +263,7 @@ client_destroy(Client *c) { ewmh_destroyclient(c); group_remove(c); + client_seturgent(c, false, UrgClient); event("DestroyClient %C\n", c); flushenterevents(); @@ -692,17 +693,19 @@ updatemwm(Client *c) { int n; /* To quote Metacity, or KWin quoting Metacity: + * * We support MWM hints deemed non-stupid + * * Our definition of non-stupid is a bit less lenient than * theirs, though. In fact, we don't really even support the * idea of supporting the hints that we support, but apps * like xmms (which noone should use) break if we don't. */ - n = getprop_long(&c->w, "_MOTIF_WM_HINTS", "_MOTIF_WM_HINTS", - 0L, (long**)&ret, 3L); + n = getprop_ulong(&c->w, "_MOTIF_WM_HINTS", "_MOTIF_WM_HINTS", + 0L, &ret, 3L); - /* FIXME: Should somehow handle all frames. */ + /* FIXME: Should somehow handle all frames of a client. */ if(c->sel) r = client_grav(c, ZR); diff --git a/cmd/wmii/column.c b/cmd/wmii/column.c index f41625b0..602da4e3 100644 --- a/cmd/wmii/column.c +++ b/cmd/wmii/column.c @@ -142,18 +142,20 @@ column_scale(Area *a) { uint minh, yoff, dy; uint ncol, nuncol; uint colh, uncolh; - int surplus, i, j; + int surplus, osurplus, i, j; if(!a->frame) return; + /* The minimum heights of collapsed and uncollpsed frames. + */ minh = labelh(def.font); colh = labelh(def.font); - uncolh = minh + colh +1; + uncolh = minh + colh + 1; + /* Count collapsed and uncollapsed frames. */ ncol = 0; nuncol = 0; - dy = 0; for(f=a->frame; f; f=f->anext) { frame_resize(f, f->r); if(f->collapsed) @@ -162,11 +164,13 @@ column_scale(Area *a) { nuncol++; } - surplus = Dy(a->r) - (ncol * colh) - (nuncol * uncolh); + surplus = Dy(a->r) + - (ncol * colh) + - (nuncol * uncolh); /* Collapse until there is room */ if(surplus < 0) { - i = ceil((float)(-surplus) / (uncolh - colh)); + i = ceil(-1.F * surplus / (uncolh - colh)); if(i >= nuncol) i = nuncol - 1; nuncol -= i; @@ -175,74 +179,94 @@ column_scale(Area *a) { } /* Push to the floating layer until there is room */ if(surplus < 0) { - i = ceil((float)(-surplus)/colh); + i = ceil(-1.F * surplus / colh); if(i > ncol) i = ncol; ncol -= i; - /* surplus += i * colh; */ + surplus += i * colh; } + /* Decide which to collapse and which to float. */ j = nuncol - 1; i = ncol - 1; - /* Decide which to collapse, float */ for(fp=&a->frame; *fp;) { f = *fp; - if(f == a->sel) - i++, j++; - if(f->collapsed) { - if(i < 0 && (f != a->sel)) { - f->collapsed = false; - area_moveto(f->view->area, f); - continue; + if(f != a->sel) { + if(!f->collapsed) { + if(j < 0) + f->collapsed = true; + j--; + } + if(f->collapsed) { + if(i < 0) { + f->collapsed = false; + area_moveto(f->view->area, f); + continue; + } + i--; } - i--; - }else { - if(j < 0 && (f != a->sel)) - f->collapsed = true; - j--; } /* Doesn't change if we 'continue' */ fp = &f->anext; } - surplus = 0; + /* Make some adjustments. */ + surplus = Dy(a->r); for(f=a->frame; f; f=f->anext) { f->r = rectsubpt(f->r, f->r.min); - f->crect = rectsubpt(f->crect, f->crect.min); f->r.max.x = Dx(a->r); if(f->collapsed) { + surplus -= colh; + f->dy = 0; f->r.max.y = colh; }else { + surplus -= uncolh; + f->dy = Dy(f->r); f->r.max.y = uncolh; - dy += Dy(f->crect); } - surplus += Dy(f->r); } - for(f = a->frame; f; f = f->anext) - f->ratio = (float)Dy(f->crect)/dy; - j = 0; - surplus = Dy(a->r) - surplus; - while(surplus > 0 && surplus != j) { - j = surplus; + /* Distribute the surplus. + * When a frame doesn't accept its allocation, don't try to + * allocate to it again. Keep going until we have no more + * surplus, or no more frames will accept it. + */ + osurplus = 0; + while(surplus > 0 && surplus != osurplus) { + osurplus = surplus; dy = 0; - for(f=a->frame; f; f=f->anext) { - if(!f->collapsed) - f->r.max.y += f->ratio * surplus; - frame_resize(f, f->r); - dy += Dy(f->r); - } - surplus = Dy(a->r) - dy; + for(f=a->frame; f; f=f->anext) + if(f->dy) + dy += f->dy; + for(f=a->frame; f; f=f->anext) + if(f->dy) { + i = Dy(f->r); + f->r.max.y += ((float)f->dy / dy) * osurplus; + + frame_resize(f, f->r); + + f->r.max.y = Dy(f->crect) + labelh(def.font) + 1; + surplus -= Dy(f->r) - i; + f->dy = Dy(f->r); + + if(Dy(f->r) == i) + f->dy = 0; + } } - for(f=a->frame; f && surplus > 0; f=f->anext) { + + /* Now, try to give each frame, in turn, the entirety of the + * surplus that we have left. A single frame might be able + * to fill its increment gap with all of what's left, but + * not with its fair share. + */ + for(f=a->frame; f && surplus > 0; f=f->anext) if(!f->collapsed) { dy = Dy(f->r); f->r.max.y += surplus; frame_resize(f, f->r); f->r.max.y = Dy(f->crect) + labelh(def.font) + 1; surplus -= Dy(f->r) - dy; - } } if(surplus < 0) { @@ -250,11 +274,15 @@ column_scale(Area *a) { surplus = 0; } + /* Adjust the y coordnates of each frame. */ yoff = a->r.min.y; i = nuncol; for(f=a->frame; f; f=f->anext) { - f->r = rectaddpt(f->r, Pt(a->r.min.x, yoff)); - + f->r = rectaddpt(f->r, + Pt(a->r.min.x, yoff)); + /* Give each frame an equal portion of the surplus, + * whether it wants it or not. + */ if(!f->collapsed) { i--; f->r.max.y += surplus / nuncol; diff --git a/cmd/wmii/dat.h b/cmd/wmii/dat.h index 6e24650f..2f0128d3 100644 --- a/cmd/wmii/dat.h +++ b/cmd/wmii/dat.h @@ -189,7 +189,7 @@ struct Frame { int column; ushort id; bool collapsed; - float ratio; + int dy; Rectangle r; Rectangle colr; Rectangle floatr; diff --git a/cmd/wmii/fns.h b/cmd/wmii/fns.h index 80419df7..072a36aa 100644 --- a/cmd/wmii/fns.h +++ b/cmd/wmii/fns.h @@ -225,12 +225,17 @@ void view_update_all(void); void view_update_rect(View*); Rectangle* view_rects(View*, uint *num, Frame *ignore); -/* util.c */ +/* _util.c */ +void backtrace(void); +void closeexec(int); char** comm(int, char**, char**); +int doublefork(void); void grep(char**, Reprog*, int); char* join(char**, char*); void refree(Regex*); void reinit(Regex*, char*); +int spawn3(int[3], const char*, char*[]); +int spawn3l(int[3], const char*, ...); void uniq(char**); /* utf.c */ diff --git a/cmd/wmii/frame.c b/cmd/wmii/frame.c index 3cb97bc4..21c688f6 100644 --- a/cmd/wmii/frame.c +++ b/cmd/wmii/frame.c @@ -246,7 +246,6 @@ Handlers framehandler = { .motion = motion_event, }; -/* These must die!!! */ Rectangle frame_rect2client(Client *c, Rectangle r, bool floating) { @@ -301,8 +300,12 @@ frame_resize(Frame *f, Rectangle r) { Rectangle fr, cr; int collapsed, dx; - if(Dx(r) <= 0 || Dy(r) <= 0) - die("Frame rect: %R\n", r); + if(Dx(r) <= 0 || Dy(r) <= 0) { + fprint(2, "Frame rect: %R\n", r); + backtrace(); + r.max.x = min(r.min.x+1, r.max.x); + r.max.y = min(r.min.y+1, r.max.y); + } c = f->client; if(c->fullscreen) { diff --git a/cmd/wmii/main.c b/cmd/wmii/main.c index 0ffedd91..2af3c7dc 100644 --- a/cmd/wmii/main.c +++ b/cmd/wmii/main.c @@ -7,12 +7,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include "fns.h" @@ -212,36 +210,6 @@ cleanup_handler(int signal) { } } -static void -closeexec(int fd) { - if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("can't set %d close on exec: %r", fd); -} - -static int -doublefork(void) { - pid_t pid; - int status; - - switch(pid=fork()) { - case -1: - fatal("Can't fork(): %r"); - case 0: - switch(pid=fork()) { - case -1: - fatal("Can't fork(): %r"); - case 0: - return 0; - default: - exit(0); - } - default: - waitpid(pid, &status, 0); - return pid; - } - /* NOTREACHED */ -} - static void init_traps(void) { char buf[1];