ref: 11948e5234a86097c64e59fdf0a7507e834ad362
author: sirjofri <sirjofri@sirjofri.de>
date: Sun Sep 1 09:39:51 EDT 2024
adds files
--- /dev/null
+++ b/Readme.txt
@@ -1,0 +1,41 @@
+
+ WINVIEW(1) WINVIEW(1)
+
+ NAME
+ winview - visual winwatch
+
+ SYNOPSIS
+ winview [ -w windir ] [ -x amount ] [ -t milliseconds ]
+
+ DESCRIPTION
+ Winview behaves like winwatch(1), but it displays downscaled
+ screenshots of the windows.
+
+ The windir parameter is used to specify the rio filesystem,
+ default is /dev/wsys. The amount parameter determines how
+ much to downscale the windows. Windows will be halved
+ amount times, for example a value of 4 halves the windows 4
+ times. Valid values for amount are from 1 to 5.
+ Milliseconds is the amount of milliseconds to wait for each
+ update.
+
+ General usage is very similar to winwatch:
+
+ • Left mouse button to activate the window.
+
+ • Middle mouse button to set the window label.
+
+ • Right mouse button to (un)hide the window.
+
+ The amount value can also be adjusted at runtime by using
+ the , and . keys.
+
+ SOURCE
+ winview.c
+
+ SEE ALSO
+ winwatch(1)
+
+ BUGS
+ Sure.
+
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,15 @@
+</$objtype/mkfile
+
+TARG=winview
+OFILES=winview.$O
+
+</sys/src/cmd/mkone
+
+man:V: Readme.txt
+
+Readme.txt: winview1
+ @{
+ rfork n
+ bind . /sys/man/1
+ man 1 $prereq > $target
+ }
--- /dev/null
+++ b/winview.c
@@ -1,0 +1,589 @@
+#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();
+ }
+}
--- /dev/null
+++ b/winview1
@@ -1,0 +1,62 @@
+.TH WINVIEW 1
+.SH NAME
+winview \- visual winwatch
+.SH SYNOPSIS
+.B winview
+[
+.B -w
+.I windir
+]
+[
+.B -x
+.I amount
+]
+[
+.B -t
+.I milliseconds
+]
+.SH DESCRIPTION
+.I Winview
+behaves like
+.IR winwatch (1),
+but it displays downscaled screenshots of the windows.
+.PP
+The
+.I windir
+parameter is used to specify the rio filesystem, default is
+.IR /dev/wsys .
+The
+.I amount
+parameter determines how much to downscale the windows.
+Windows will be halved
+.I amount
+times, for example a value of
+.I 4
+halves the windows 4 times.
+Valid values for
+.I amount
+are from 1 to 5.
+.I Milliseconds
+is the amount of milliseconds to wait for each update.
+.PP
+General usage is very similar to winwatch:
+.IP •
+Left mouse button to activate the window.
+.IP •
+Middle mouse button to set the window label.
+.IP •
+Right mouse button to (un)hide the window.
+.PP
+The
+.I amount
+value can also be adjusted at runtime by using the
+.I ,
+and
+.I .
+keys.
+.SH SOURCE
+.B winview.c
+.SH SEE ALSO
+.IR winwatch (1)
+.SH BUGS
+Sure.