winwatch: Plan 9-ify.

This is new code, and custom to plan9port.  Make it
conform more closely to plan9 style.

Signed-off-by: Dan Cross <cross@gajendra.net>
This commit is contained in:
Dan Cross 2020-01-15 14:47:39 +00:00 committed by Dan Cross
parent 0ac4bfee32
commit 6510a2d353

View file

@ -1,23 +1,25 @@
/* slightly modified from /*
https://github.com/fhs/misc/blob/master/cmd/winwatch/winwatch.c * slightly modified from
so as to deal with memory leaks and certain X errors */ * https://github.com/fhs/misc/blob/master/cmd/winwatch/winwatch.c
* so as to deal with memory leaks and certain X errors
*/
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include <draw.h> #include <draw.h>
#include <event.h> #include <event.h>
#include <regexp.h> #include <regexp.h>
#include <stdio.h> #include <fmt.h>
#include "../devdraw/x11-inc.h" #include "../devdraw/x11-inc.h"
AUTOLIB(X11); AUTOLIB(X11);
typedef struct Win Win; typedef struct Win Win;
struct Win { struct Win {
XWindow n; XWindow n;
int dirty; int dirty;
char *label; char *label;
Rectangle r; Rectangle r;
}; };
XDisplay *dpy; XDisplay *dpy;
@ -37,8 +39,8 @@ Image *lightblue;
XErrorHandler oldxerrorhandler; XErrorHandler oldxerrorhandler;
enum { enum {
PAD = 3, PAD = 3,
MARGIN = 5 MARGIN = 5
}; };
static jmp_buf savebuf; static jmp_buf savebuf;
@ -46,115 +48,111 @@ static jmp_buf savebuf;
int int
winwatchxerrorhandler(XDisplay *disp, XErrorEvent *xe) winwatchxerrorhandler(XDisplay *disp, XErrorEvent *xe)
{ {
char buf[100]; char buf[100];
XGetErrorText(disp, xe->error_code, buf, 100); XGetErrorText(disp, xe->error_code, buf, 100);
fprintf(stderr, "winwatch: X error %s, request code %d\n", buf, fprint(2, "winwatch: X error %s, request code %d\n",
xe->request_code); buf, xe->request_code);
XFlush(disp); XFlush(disp);
XSync(disp, False); XSync(disp, False);
XSetErrorHandler(oldxerrorhandler); XSetErrorHandler(oldxerrorhandler);
longjmp(savebuf, 1); longjmp(savebuf, 1);
return(0); /* Not reached */
} }
void* void*
erealloc(void *v, ulong n) erealloc(void *v, ulong n)
{ {
v = realloc(v, n); v = realloc(v, n);
if (v == nil) if(v==nil)
sysfatal("out of memory reallocating"); sysfatal("out of memory reallocating");
return v; return v;
} }
char* char*
estrdup(char *s) estrdup(char *s)
{ {
s = strdup(s); s = strdup(s);
if (s == nil) if(s==nil)
sysfatal("out of memory allocating"); sysfatal("out of memory allocating");
return s; return(s);
} }
char* char*
getproperty(XWindow w, Atom a) getproperty(XWindow w, Atom a)
{ {
uchar *p; uchar *p;
int fmt; int fmt;
Atom type; Atom type;
ulong n, dummy; ulong n, dummy;
int s; int s;
n = 100; n = 100;
p = nil; p = nil;
oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler);
s = XGetWindowProperty(dpy, w, a, 0, 100L, 0,
AnyPropertyType, &type, &fmt, &n, &dummy, &p);
XFlush(dpy);
XSync(dpy, False);
XSetErrorHandler(oldxerrorhandler);
if(s!=0){
XFree(p);
return(nil);
}
oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); return((char*)p);
s = XGetWindowProperty(dpy, w, a, 0, 100L, 0,
AnyPropertyType, &type, &fmt, &n, &dummy, &p);
XFlush(dpy);
XSync(dpy, False);
XSetErrorHandler(oldxerrorhandler);
if (s == 0)
return (char *) p;
else {
free(p);
return nil;
}
} }
XWindow XWindow
findname(XWindow w) findname(XWindow w)
{ {
int i; int i;
uint nxwin; uint nxwin;
XWindow dw1, dw2, *xwin; XWindow dw1, dw2, *xwin;
char *p; char *p;
int s; int s;
Atom net_wm_name; Atom net_wm_name;
p = getproperty(w, XA_WM_NAME); p = getproperty(w, XA_WM_NAME);
if (p) { if(p){
free(p); free(p);
return w; return(w);
} }
net_wm_name = XInternAtom (dpy, "_NET_WM_NAME", FALSE); net_wm_name = XInternAtom(dpy, "_NET_WM_NAME", FALSE);
p = getproperty(w, net_wm_name); p = getproperty(w, net_wm_name);
if (p) { if(p){
free(p); free(p);
return w; return(w);
} }
oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler);
s = XQueryTree(dpy, w, &dw1, &dw2, &xwin, &nxwin); s = XQueryTree(dpy, w, &dw1, &dw2, &xwin, &nxwin);
XFlush(dpy); XFlush(dpy);
XSync(dpy, False); XSync(dpy, False);
XSetErrorHandler(oldxerrorhandler); XSetErrorHandler(oldxerrorhandler);
if(s == 0) {
if (xwin != NULL)
XFree(xwin);
return 0;
}
if (s == 0) { for (i = 0; i < nxwin; i++) {
if (xwin != NULL) w = findname(xwin[i]);
XFree(xwin); if (w != 0) {
return 0; XFree(xwin);
} return w;
}
}
XFree(xwin);
for (i = 0; i < nxwin; i++) { return 0;
w = findname(xwin[i]);
if (w != 0) {
XFree(xwin);
return w;
}
}
XFree(xwin);
return 0;
} }
int int
wcmp(const void *w1, const void *w2) wcmp(const void *w1, const void *w2)
{ {
return *(XWindow *) w1 - *(XWindow *) w2; return *(XWindow *) w1 - *(XWindow *) w2;
} }
/* unicode-aware case-insensitive strcmp, taken from golangs gc/subr.c */ /* unicode-aware case-insensitive strcmp, taken from golangs gc/subr.c */
@ -162,377 +160,365 @@ wcmp(const void *w1, const void *w2)
int int
_cistrcmp(char *p, char *q) _cistrcmp(char *p, char *q)
{ {
Rune rp, rq; Rune rp, rq;
while(*p || *q) { while(*p || *q) {
if(*p == 0) if(*p == 0)
return +1; return +1;
if(*q == 0) if(*q == 0)
return -1; return -1;
p += chartorune(&rp, p); p += chartorune(&rp, p);
q += chartorune(&rq, q); q += chartorune(&rq, q);
rp = tolowerrune(rp); rp = tolowerrune(rp);
rq = tolowerrune(rq); rq = tolowerrune(rq);
if(rp < rq) if(rp < rq)
return -1; return -1;
if(rp > rq) if(rp > rq)
return +1; return +1;
} }
return 0; return 0;
} }
int int
winlabelcmp(const void *w1, const void *w2) winlabelcmp(const void *w1, const void *w2)
{ {
const Win *p1 = (Win *) w1; const Win *p1 = (Win *) w1;
const Win *p2 = (Win *) w2; const Win *p2 = (Win *) w2;
return _cistrcmp(p1->label, p2->label); return _cistrcmp(p1->label, p2->label);
} }
void void
refreshwin(void) refreshwin(void)
{ {
XWindow dw1, dw2, *xwin; XWindow dw1, dw2, *xwin;
XClassHint class; XClassHint class;
XWindowAttributes attr; XWindowAttributes attr;
char *label; char *label;
char *wmname; char *wmname;
int i, nw; int i, nw;
uint nxwin; uint nxwin;
Status s; Status s;
Atom net_wm_name; Atom net_wm_name;
oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler);
s = XQueryTree(dpy, root, &dw1, &dw2, &xwin, &nxwin); s = XQueryTree(dpy, root, &dw1, &dw2, &xwin, &nxwin);
XFlush(dpy); XFlush(dpy);
XSync(dpy, False); XSync(dpy, False);
XSetErrorHandler(oldxerrorhandler); XSetErrorHandler(oldxerrorhandler);
if(s==0){
if(xwin!=NULL)
XFree(xwin);
return;
}
qsort(xwin, nxwin, sizeof(xwin[0]), wcmp);
if (s == 0) { nw = 0;
if (xwin != NULL) for(i=0; i<nxwin; i++){
XFree(xwin); memset(&attr, 0, sizeof attr);
return; xwin[i] = findname(xwin[i]);
} if(xwin[i]==0)
qsort(xwin, nxwin, sizeof(xwin[0]), wcmp); continue;
nw = 0; oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler);
for (i = 0; i < nxwin; i++) { s = XGetWindowAttributes(dpy, xwin[i], &attr);
memset(&attr, 0, sizeof attr); XFlush(dpy);
xwin[i] = findname(xwin[i]); XSync(dpy, False);
if (xwin[i] == 0) XSetErrorHandler(oldxerrorhandler);
continue; if(s==0)
continue;
if (attr.width <= 0 ||
attr.override_redirect ||
attr.map_state != IsViewable)
continue;
oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler);
s = XGetWindowAttributes(dpy, xwin[i], &attr); s = XGetClassHint(dpy, xwin[i], &class);
XFlush(dpy); XFlush(dpy);
XSync(dpy, False); XSync(dpy, False);
XSetErrorHandler(oldxerrorhandler); XSetErrorHandler(oldxerrorhandler);
if (s == 0) if(s==0)
continue; continue;
if (attr.width <= 0 || attr.override_redirect
|| attr.map_state != IsViewable)
continue;
oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); if (exclude!=nil && regexec(exclude, class.res_name, nil, 0)) {
s = XGetClassHint(dpy, xwin[i], &class); free(class.res_name);
XFlush(dpy); free(class.res_class);
XSync(dpy, False); continue;
XSetErrorHandler(oldxerrorhandler); }
if (s == 0) net_wm_name = XInternAtom(dpy, "_NET_WM_NAME", FALSE);
continue; wmname = getproperty(xwin[i], net_wm_name);
if (exclude != nil && regexec(exclude, class.res_name, nil, 0)) { if(wmname==nil){
free(class.res_name); wmname = getproperty(xwin[i], XA_WM_NAME);
free(class.res_class); if(wmname==nil){
continue; free(class.res_name);
} free(class.res_class);
continue;
}
}
net_wm_name = XInternAtom (dpy, "_NET_WM_NAME", FALSE); label = class.res_name;
wmname = getproperty(xwin[i], net_wm_name); if(showwmnames==1)
label = wmname;
if (wmname == nil) { if(nw<nwin && win[nw].n==xwin[i] && strcmp(win[nw].label, label)==0) {
wmname = getproperty(xwin[i], XA_WM_NAME); nw++;
if (wmname == nil) { free(wmname);
free(class.res_name); free(class.res_name);
free(class.res_class); free(class.res_class);
continue; continue;
} }
}
if (showwmnames == 1) if(nw<nwin){
label = wmname; free(win[nw].label);
else win[nw].label = nil;
label = class.res_name; }
if (nw < nwin && win[nw].n == xwin[i] if(nw>=mwin){
&& strcmp(win[nw].label, label) == 0) { mwin += 8;
nw++; win = erealloc(win, mwin * sizeof(win[0]));
free(wmname); }
free(class.res_name); win[nw].n = xwin[i];
free(class.res_class); win[nw].label = estrdup(label);
continue; win[nw].dirty = 1;
} win[nw].r = Rect(0, 0, 0, 0);
free(wmname);
free(class.res_name);
free(class.res_class);
nw++;
}
if (nw < nwin) { oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler);
free(win[nw].label); XFree(xwin);
win[nw].label = nil; XFlush(dpy);
} XSync(dpy, False);
XSetErrorHandler(oldxerrorhandler);
if (nw >= mwin) { while(nwin>nw)
mwin += 8; free(win[--nwin].label);
win = erealloc(win, mwin * sizeof(win[0])); nwin = nw;
}
win[nw].n = xwin[i];
win[nw].label = estrdup(label);
win[nw].dirty = 1;
win[nw].r = Rect(0, 0, 0, 0);
free(wmname);
free(class.res_name);
free(class.res_class);
nw++;
}
oldxerrorhandler = XSetErrorHandler(winwatchxerrorhandler); if(sortlabels==1)
XFree(xwin); qsort(win, nwin, sizeof(struct Win), winlabelcmp);
XFlush(dpy);
XSync(dpy, False);
XSetErrorHandler(oldxerrorhandler);
while (nwin > nw)
free(win[--nwin].label);
nwin = nw;
if (sortlabels == 1)
qsort(win, nwin, sizeof(struct Win), winlabelcmp);
return;
} }
void void
drawnowin(int i) drawnowin(int i)
{ {
Rectangle r; Rectangle r;
r = Rect(0, 0, (Dx(screen->r) - 2 * MARGIN + PAD) / cols - PAD, r = Rect(0, 0, (Dx(screen->r) - 2 * MARGIN + PAD) / cols - PAD, font->height);
font->height); r = rectaddpt(
r = rectaddpt(rectaddpt rectaddpt(r,
(r, Pt(MARGIN + (PAD + Dx(r)) * (i / rows),
Pt(MARGIN + (PAD + Dx(r)) * (i / rows), MARGIN + (PAD + Dy(r)) * (i % rows))),
MARGIN + (PAD + Dy(r)) * (i % rows))), screen->r.min);
screen->r.min); draw(screen, insetrect(r, -1), lightblue, nil, ZP);
draw(screen, insetrect(r, -1), lightblue, nil, ZP);
} }
void void
drawwin(int i) drawwin(int i)
{ {
draw(screen, win[i].r, lightblue, nil, ZP); draw(screen, win[i].r, lightblue, nil, ZP);
_string(screen, addpt(win[i].r.min, Pt(2, 0)), display->black, ZP, _string(screen, addpt(win[i].r.min, Pt(2, 0)), display->black, ZP,
font, win[i].label, nil, strlen(win[i].label), font, win[i].label, nil, strlen(win[i].label),
win[i].r, nil, ZP, SoverD); win[i].r, nil, ZP, SoverD);
border(screen, win[i].r, 1, display->black, ZP); border(screen, win[i].r, 1, display->black, ZP);
win[i].dirty = 0; win[i].dirty = 0;
} }
int int
geometry(void) geometry(void)
{ {
int i, ncols, z; int i, ncols, z;
Rectangle r; Rectangle r;
z = 0; z = 0;
rows = (Dy(screen->r) - 2 * MARGIN + PAD) / (font->height + PAD); rows = (Dy(screen->r) - 2 * MARGIN + PAD) / (font->height + PAD);
if (rows * cols < nwin || rows * cols >= nwin * 2) { if(rows*cols<nwin || rows*cols>=nwin*2){
ncols = nwin <= 0 ? 1 : (nwin + rows - 1) / rows; ncols = 1;
if (ncols != cols) { if(nwin>0)
cols = ncols; ncols = (nwin + rows - 1) / rows;
z = 1; if(ncols!=cols){
} cols = ncols;
} z = 1;
}
}
r = Rect(0, 0, (Dx(screen->r) - 2 * MARGIN + PAD) / cols - PAD, r = Rect(0, 0, (Dx(screen->r) - 2 * MARGIN + PAD) / cols - PAD, font->height);
font->height); for(i=0; i<nwin; i++)
for (i = 0; i < nwin; i++) win[i].r =
win[i].r = rectaddpt(
rectaddpt(rectaddpt rectaddpt(r,
(r, Pt(MARGIN + (PAD + Dx(r)) * (i / rows),
Pt(MARGIN + (PAD + Dx(r)) * (i / rows), MARGIN + (PAD + Dy(r)) * (i % rows))),
MARGIN + (PAD + Dy(r)) * (i % rows))), screen->r.min);
screen->r.min);
return z; return z;
} }
void void
redraw(Image *screen, int all) redraw(Image *screen, int all)
{ {
int i; int i;
all |= geometry(); all |= geometry();
if (all) if(all)
draw(screen, screen->r, lightblue, nil, ZP); draw(screen, screen->r, lightblue, nil, ZP);
for (i = 0; i < nwin; i++) for(i=0; i<nwin; i++)
if (all || win[i].dirty) if(all || win[i].dirty)
drawwin(i); drawwin(i);
if (!all) if(!all)
for (; i < onwin; i++) for (; i<onwin; i++)
drawnowin(i); drawnowin(i);
onwin = nwin;
onwin = nwin;
} }
void void
eresized(int new) eresized(int new)
{ {
if (new && getwindow(display, Refmesg) < 0) if(new && getwindow(display, Refmesg)<0)
fprint(2, "can't reattach to window"); fprint(2, "can't reattach to window");
geometry(); geometry();
redraw(screen, 1); redraw(screen, 1);
} }
void void
selectwin(XWindow win) selectwin(XWindow win)
{ {
XEvent ev; XEvent ev;
long mask; long mask;
memset(&ev, 0, sizeof ev); memset(&ev, 0, sizeof ev);
ev.xclient.type = ClientMessage; ev.xclient.type = ClientMessage;
ev.xclient.serial = 0; ev.xclient.serial = 0;
ev.xclient.send_event = True; ev.xclient.send_event = True;
ev.xclient.message_type = net_active_window; ev.xclient.message_type = net_active_window;
ev.xclient.window = win; ev.xclient.window = win;
ev.xclient.format = 32; ev.xclient.format = 32;
mask = SubstructureRedirectMask | SubstructureNotifyMask; mask = SubstructureRedirectMask | SubstructureNotifyMask;
XSendEvent(dpy, root, False, mask, &ev); XSendEvent(dpy, root, False, mask, &ev);
XMapRaised(dpy, win); XMapRaised(dpy, win);
XSync(dpy, False); XSync(dpy, False);
} }
void void
click(Mouse m) click(Mouse m)
{ {
int i, j; int i, j;
if (m.buttons == 0 || (m.buttons & ~4)) if(m.buttons==0 || (m.buttons&~4))
return; return;
for (i = 0; i < nwin; i++) for(i=0; i<nwin; i++)
if (ptinrect(m.xy, win[i].r)) if(ptinrect(m.xy, win[i].r))
break; break;
if (i == nwin) if(i==nwin)
return; return;
do do
m = emouse(); m = emouse();
while (m.buttons == 4); while(m.buttons==4);
if (m.buttons != 0) { if(m.buttons!=0){
do do
m = emouse(); m = emouse();
while (m.buttons); while(m.buttons);
return; return;
} }
for(j=0; j<nwin; j++)
for (j = 0; j < nwin; j++) if(ptinrect(m.xy, win[j].r))
if (ptinrect(m.xy, win[j].r)) break;
break; if(j==i)
if (j != i) selectwin(win[i].n);
return;
selectwin(win[i].n);
} }
void void
usage(void) usage(void)
{ {
fprint(2, fprint(2,
"usage: winwatch [-e exclude] [-W winsize] [-f font] [-n] [-s]\n"); "usage: winwatch [-e exclude] [-W winsize] [-f font] [-n] [-s]\n");
exits("usage"); exits("usage");
} }
void void
main(int argc, char **argv) main(int argc, char **argv)
{ {
char *fontname; char *fontname;
int Etimer; int Etimer;
Event e; Event e;
sortlabels = 0; sortlabels = 0;
showwmnames = 0; showwmnames = 0;
fontname = "/lib/font/bit/lucsans/unicode.8.font";
fontname = "/lib/font/bit/lucsans/unicode.8.font"; ARGBEGIN {
case 'W':
winsize = EARGF(usage());
break;
case 'f':
fontname = EARGF(usage());
break;
case 'e':
exclude = regcomp(EARGF(usage()));
if(exclude==nil)
sysfatal("Bad regexp");
break;
case 's':
sortlabels = 1;
break;
case 'n':
showwmnames = 1;
break;
default:
usage();
} ARGEND;
ARGBEGIN { if(argc)
case 'W': usage();
winsize = EARGF(usage());
break;
case 'f':
fontname = EARGF(usage());
break;
case 'e':
exclude = regcomp(EARGF(usage()));
if (exclude == nil)
sysfatal("Bad regexp");
break;
case 's':
sortlabels = 1;
break;
case 'n':
showwmnames = 1;
break;
default:
usage();
}
ARGEND if (argc)
usage();
/* moved up from original winwatch.c for p9p because there can be only one but we want to restart when needed */ /* moved up from original winwatch.c for p9p because there can be only one but we want to restart when needed */
einit(Emouse | Ekeyboard); einit(Emouse | Ekeyboard);
Etimer = etimer(0, 1000); Etimer = etimer(0, 1000);
dpy = XOpenDisplay(""); dpy = XOpenDisplay("");
if(dpy==nil)
sysfatal("open display: %r");
if (dpy == nil) root = DefaultRootWindow(dpy);
sysfatal("open display: %r"); net_active_window = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
root = DefaultRootWindow(dpy); initdraw(0, 0, "winwatch");
net_active_window = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); lightblue = allocimagemix(display, DPalebluegreen, DWhite);
if(lightblue==nil)
sysfatal("allocimagemix: %r");
font = openfont(display, fontname);
if(font==nil)
sysfatal("font '%s' not found", fontname);
initdraw(0, 0, "winwatch"); /* reentry point upon X server errors */
lightblue = allocimagemix(display, DPalebluegreen, DWhite); setjmp(savebuf);
if (lightblue == nil)
sysfatal("allocimagemix: %r");
if ((font = openfont(display, fontname)) == nil)
sysfatal("font '%s' not found", fontname);
refreshwin();
/* reentry point upon X server errors */ redraw(screen, 1);
setjmp(savebuf); for(;;){
switch(eread(Emouse|Ekeyboard|Etimer, &e)){
refreshwin(); case Ekeyboard:
redraw(screen, 1); if(e.kbdc==0x7F || e.kbdc=='q')
exits(0);
for (;;) { break;
switch (eread(Emouse | Ekeyboard | Etimer, &e)) { case Emouse:
case Ekeyboard: if(e.mouse.buttons)
if (e.kbdc == 0x7F || e.kbdc == 'q') click(e.mouse);
exits(0); /* fall through */
break; default: /* Etimer */
case Emouse: refreshwin();
if (e.mouse.buttons) redraw(screen, 0);
click(e.mouse); break;
/* fall through */ }
default: /* Etimer */ }
refreshwin();
redraw(screen, 0);
break;
}
}
} }