Fix column scaling a bit.

This commit is contained in:
Kris Maglione 2008-02-09 13:23:27 -05:00
parent 5bb7a777a8
commit 443c6cbe66
8 changed files with 230 additions and 83 deletions

View File

@ -2,6 +2,10 @@
* See LICENSE file for license details.
*/
#include "dat.h"
#include <errno.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <unistd.h>
#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) {

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -189,7 +189,7 @@ struct Frame {
int column;
ushort id;
bool collapsed;
float ratio;
int dy;
Rectangle r;
Rectangle colr;
Rectangle floatr;

View File

@ -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 */

View File

@ -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) {

View File

@ -7,12 +7,10 @@
#include <X11/Xproto.h>
#include <X11/cursorfont.h>
#include <errno.h>
#include <fcntl.h>
#include <locale.h>
#include <pwd.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#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];