ref: 0729f86ea9233ed4e2e7881fe5ac8aee735c78ee
dir: /winview.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <event.h>
#include <cursor.h>
void
usage(void)
{
fprint(2, "usage: %s\n", argv0);
exits("usage");
}
char *windir = "/dev/wsys";
char *wintitle = "winview";
typedef struct Win Win;
struct Win {
char *name;
};
Win *windows = nil;
int numwindows = 0;
Point cellsize;
Point cells;
Point halfcell;
Point hovercell = {0, 0};
int smaller = 2;
void
reallocwindows(int num)
{
int i;
if (windows) {
for (i = 0; i < numwindows; i++) {
if (windows[i].name)
free(windows[i].name);
}
free(windows);
}
numwindows = num;
windows = mallocz(numwindows * sizeof(Win), 1);
}
int
getwid(void)
{
int n;
n = hovercell.y * cells.x + hovercell.x;
if (n >= numwindows)
return -1;
return n;
}
Point
clampinrect(Point xy, Rectangle r)
{
if (xy.x < r.min.x)
xy.x = r.min.x;
if (xy.y < r.min.y)
xy.y = r.min.y;
if (xy.x > r.max.x)
xy.x = r.max.x;
if (xy.y > r.max.y)
xy.y = r.max.y;
return xy;
}
uchar
ilerp(uchar A, uchar B, double α)
{
ulong a = A;
ulong b = B;
return (b * α) + (a * (1. - α));
}
Memimage*
downsample(Memimage *i)
{
Memimage *t;
Rectangle r;
Point xy;
Point fxy;
uchar *fp, *tp;
int c, px;
if (!i)
sysfatal("%r");
r = i->r;
r.min.x /= 2;
r.min.y /= 2;
r.max.x /= 2;
r.max.y /= 2;
if (Dx(r) <= 0 || Dy(r) <= 0)
return nil;
t = allocmemimage(r, i->chan);
if (!t)
sysfatal("%r");
for (xy.y = r.min.y; xy.y < r.max.y; xy.y++) {
for (xy.x = r.min.x; xy.x < r.max.x; xy.x++) {
tp = byteaddr(t, xy);
fxy = mulpt(xy, 2);
for (px = 0; px < 4; px++) {
switch (px) {
case 0:
/* empty: top left */
break;
case 1:
fxy.x++; /* top right */
break;
case 2:
fxy.y++; /* bottom right */
break;
case 3:
fxy.x--; /* bottom left */
break;
}
for (c = 0; c < i->nchan; c++) {
fp = byteaddr(i, clampinrect(fxy, i->r));
if (c == 0) {
tp[c] = fp[c];
continue;
}
tp[c] = ilerp(tp[c], fp[c], 0.5);
}
}
}
}
return t;
}
int
ishidden(char *win)
{
char buf[6*12];
char *tokens[6];
char *s;
int fd;
s = smprint("%s/%s/wctl", windir, win);
if (!s)
sysfatal("%r");
fd = open(s, OREAD);
free(s);
if (fd < 0)
sysfatal("%r");
if (read(fd, buf, sizeof(buf)) != 6*12) {
close(fd);
sysfatal("short read: %r");
}
close(fd);
buf[6*12-1] = 0;
if (tokenize(buf, tokens, 6) != 6)
sysfatal("bad read of wctl file");
return strcmp(tokens[5], "hidden") == 0;
}
char*
getwinname(char *win)
{
char buf[128];
char *s;
int n;
int fd;
s = smprint("%s/%s/label", windir, win);
if (!s)
sysfatal("%r");
fd = open(s, OREAD);
free(s);
if (fd < 0)
return nil;
if ((n = read(fd, buf, 127)) <= 0) {
close(fd);
return nil;
}
close(fd);
buf[n] = 0;
s = strdup(buf);
return s;
}
int
issamewin(char *winname)
{
return strcmp(winname, wintitle) == 0;
}
Memsubfont *memdefont = nil;
Memimage *contrast = nil;
Memimage *tback = nil;
Image *green = nil;
Image *red = nil;
int
isselected(Point xy)
{
return xy.x == hovercell.x && xy.y == hovercell.y;
}
Image*
getbordercolor(int isselected, int x, int y)
{
int n;
char *w;
if (isselected)
return green;
n = y * cells.x + x;
if (n >= numwindows)
return display->white;
w = windows[n].name;
if (!w)
return display->white;
return ishidden(w) ? red : display->white;
}
void
drawgrid(void)
{
int x, y;
Rectangle r;
int i;
for (x = 0; x < cells.x; x++) {
for (y = 0; y < cells.y; y++) {
r.min.x = x * cellsize.x;
r.min.y = y * cellsize.y;
r.max.x = r.min.x + cellsize.x;
r.max.y = r.min.y + cellsize.y;
i = isselected(Pt(x, y));
border(screen, rectaddpt(r, screen->r.min),
i ? 2 : 2,
getbordercolor(i, x, y), ZP);
}
}
}
int
redrawwin(Dir *dir, Memimage *target, int num)
{
int fd, i;
char *s;
char *winname;
Memimage *m, *mn;
Point coords, txt, ts;
Rectangle textbox;
winname = getwinname(dir->name);
if (!winname)
return 0;
if (issamewin(winname)) {
free(winname);
return 0;
}
s = smprint("%s/%s/window", windir, dir->name);
if (!s)
sysfatal("%r");
fd = open(s, OREAD);
free(s);
if (fd < 0)
return 0;
m = readmemimage(fd);
close(fd);
if (!m)
return 0;
for (i = 0; i < smaller; i++) {
mn = downsample(m);
freememimage(m);
m = mn;
}
if (!m) {
fprint(2, "ignoring window %s\n", dir->name);
return 0;
}
coords.x = num % cells.x;
coords.y = num / cells.x;
coords.x *= cellsize.x;
coords.y *= cellsize.y;
coords.x += target->r.min.x;
coords.y += target->r.min.y;
memimagedraw(target, rectaddpt(m->r, coords),
m, m->r.min, nil, ZP, S);
ts = stringsize(font, winname);
txt = addpt(coords, halfcell);
txt = subpt(txt, divpt(ts, 2));
textbox.min = txt;
textbox.max = addpt(textbox.min, ts);
textbox = insetrect(textbox, -5);
memimagedraw(target, textbox, tback, ZP, nil, ZP, SoverD);
memimagestring(target, txt,
contrast, ZP, memdefont, winname);
free(winname);
if (!windows[num].name) {
windows[num].name = strdup(dir->name);
} else if (strcmp(windows[num].name, dir->name) != 0) {
free(windows[num].name);
windows[num].name = strdup(dir->name);
}
return 1;
}
Memimage *bufimg = nil;
void
update(void)
{
Dir *dirs;
int fd;
long num, l;
int i;
fd = open(windir, OREAD);
if (fd < 0)
sysfatal("%r");
num = dirreadall(fd, &dirs);
close(fd);
if (num < 0)
goto Out;
reallocwindows(num);
if (!bufimg) {
bufimg = allocmemimage(screen->r, screen->chan);
if (!bufimg)
sysfatal("%r");
}
memfillcolor(bufimg, DBlack);
i = 0;
for (l = 0; l < num; l++)
i += redrawwin(&dirs[l], bufimg, i);
l = Dy(bufimg->r) * Dx(bufimg->r) * bufimg->depth;
loadimage(screen, screen->r, bufimg->data->bdata, l);
drawgrid();
Out:
free(dirs);
}
void
eresized(int new)
{
int i, n;
if (new && getwindow(display, Refnone) < 0)
sysfatal("%r");
if (bufimg) {
freememimage(bufimg);
bufimg = nil;
}
n = 2;
for (i = 1; i < smaller; i++)
n *= 2;
cellsize.x = Dx(display->image->r) / n;
cellsize.y = Dy(display->image->r) / n;
cells.x = Dx(screen->r) / cellsize.x;
cells.y = Dy(screen->r) / cellsize.y;
halfcell = divpt(cellsize, 2);
draw(screen, screen->r, display->black, nil, ZP);
update();
}
int
getwctl(void)
{
char *w, *s;
int n;
n = getwid();
if (n < 0)
return -1;
w = windows[n].name;
if (!w)
return -1;
s = smprint("%s/%s/wctl", windir, w);
if (!s)
sysfatal("%r");
n = open(s, OWRITE);
free(s);
return n;
}
void
activatewin(void)
{
int fd;
fd = getwctl();
if (fd < 0)
return;
fprint(fd, "unhide");
fprint(fd, "top");
fprint(fd, "current");
close(fd);
}
void
hidewin(void)
{
int fd;
int h;
fd = getwctl();
if (fd < 0)
return;
h = ishidden(windows[getwid()].name);
fprint(fd, h ? "unhide" : "hide");
close(fd);
}
void
renamewin(Mouse *m)
{
int fd, n;
char *w, *s;
char buf[128];
n = getwid();
if (n < 0)
return;
w = windows[n].name;
if (!w)
return;
s = smprint("%s/%s/label", windir, w);
if (!s)
sysfatal("%r");
fd = open(s, ORDWR);
free(s);
if (fd < 0)
return;
if ((n = read(fd, buf, 127)) <= 0) {
close(n);
return;
}
buf[n] = 0;
if (!eenter("label", buf, sizeof(buf), m)) {
close(fd);
return;
}
fprint(fd, "%s", buf);
close(fd);
}
void
mouseinput(Mouse m)
{
if (m.buttons == 0) {
m.xy.x -= screen->r.min.x;
m.xy.y -= screen->r.min.y;
hovercell.x = m.xy.x / cellsize.x;
hovercell.y = m.xy.y / cellsize.y;
drawgrid();
return;
}
switch (m.buttons) {
case 4: /* right button */
hidewin();
break;
case 2: /* middle button */
renamewin(&m);
break;
case 1: /* left button */
activatewin();
break;
}
}
void
keyinput(int k)
{
switch (k) {
case '.':
smaller--;
if (smaller < 1)
smaller = 1;
goto Redraw;
case ',':
smaller++;
if (smaller > 5)
smaller = 5;
goto Redraw;
}
return;
Redraw:
eresized(0);
}
void
main(int argc, char **argv)
{
int e, timer;
int ms = 1000;
Event ev;
ARGBEGIN{
case 'w':
windir = EARGF(usage());
break;
case 'x':
smaller = atoi(EARGF(usage()));
break;
case 't':
ms = atoi(EARGF(usage()));
break;
case 'h':
usage();
break;
}ARGEND;
if (smaller < 1)
smaller = 1;
if (smaller > 5)
smaller = 5;
if (ms < 100)
ms = 100;
if (initdraw(nil, nil, wintitle) < 0)
sysfatal("%r");
if (memimageinit() < 0)
sysfatal("%r");
memdefont = getmemdefont();
contrast = allocmemimage(Rect(0, 0, 1, 1), screen->chan);
contrast->flags |= Frepl;
contrast->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
memfillcolor(contrast, DWhite);
tback = allocmemimage(Rect(0, 0, 1, 1), RGBA32);
tback->flags |= Frepl;
tback->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
memfillcolor(tback, 0x00000077);
green = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x00FF00FF);
red = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xFF0000FF);
einit(Emouse|Ekeyboard);
timer = etimer(0, ms);
eresized(0);
for (;;) {
e = event(&ev);
switch (e) {
case Emouse:
mouseinput(ev.mouse);
break;
case Ekeyboard:
if (ev.kbdc == 'q')
exits(nil);
keyinput(ev.kbdc);
break;
}
if (e == timer)
update();
}
}