ref: d48958a8da1274585911fc43dd1c6fffd7f78f8a
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; return buf; } 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; Rectangle textbox; winname = strdup(getwinname(dir->name)); if (!winname) return 0; if (issamewin(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); textbox.min = addpt(coords, halfcell); textbox.max = addpt(textbox.min, stringsize(font, winname)); textbox = insetrect(textbox, -5); memimagedraw(target, textbox, tback, ZP, nil, ZP, SoverD); memimagestring(target, addpt(coords, halfcell), contrast, ZP, memdefont, 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(); } }