wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

commit e3fdbdb5480fe549370d39f62c39bb96b0f28656
parent 9adfeea6c2da2761ba408a9fe2a22787058fcdf2
Author: Kris Maglione <kris@suckless.org>
Date:   Mon, 24 May 2010 15:17:09 -0400

Improve wistrut and build it by default. Add wistrut and wihack man pages.

Diffstat:
cmd/Makefile | 3++-
cmd/strut/dat.h | 6+++---
cmd/strut/fns.h | 2+-
cmd/strut/main.c | 127++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
cmd/strut/win.c | 29++++++++++++++---------------
cmd/wihack.sh | 1+
cmd/wmii/client.c | 4+---
cmd/wmii/ewmh.c | 3+--
cmd/wmii/layout.c | 3+--
cmd/wmii/main.c | 16+++++++---------
cmd/wmii/mouse.c | 5++---
include/stuff/util.h | 1+
include/stuff/x11.h | 3+++
lib/libstuff/Makefile | 1+
lib/libstuff/map.c | 10+++++++---
lib/libstuff/x11/properties/windowname.c | 17+++++++++++++++++
lib/libstuff/x11/windows/createwindow_visual.c | 4++++
lib/libstuff/x11/x11.h | 2--
man/Makefile | 4+++-
man/wihack.1 | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
man/wihack.man1 | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
man/wistrut.1 | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
man/wistrut.man1 | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
util/compile | 2+-
24 files changed, 422 insertions(+), 70 deletions(-)

diff --git a/cmd/Makefile b/cmd/Makefile @@ -5,7 +5,8 @@ include $(ROOT)/mk/wmii.mk wmiir.c: $(ROOT)/mk/wmii.mk DIRS = wmii \ - menu + menu \ + strut TARG = wihack \ wmii.rc \ wmii.sh \ diff --git a/cmd/strut/dat.h b/cmd/strut/dat.h @@ -11,8 +11,8 @@ # define EXTERN extern #endif -EXTERN Handlers handlers; +enum { DAuto, DHorizontal, DVertical }; -EXTERN Window win; -EXTERN Window frame; +EXTERN Handlers handlers; +EXTERN int direction; diff --git a/cmd/strut/fns.h b/cmd/strut/fns.h @@ -6,7 +6,7 @@ uint flushenterevents(void); void xevent_loop(void); void xtime_kludge(void); -void restrut(void); +void restrut(Window*); void ewmh_getstrut(Window*, Rectangle[4]); void ewmh_setstrut(Window*, Rectangle[4]); diff --git a/cmd/strut/main.c b/cmd/strut/main.c @@ -6,13 +6,19 @@ #include <X11/Xproto.h> #include <locale.h> #include <string.h> +#include <time.h> #include "fns.h" -static const char version[] = "witray-"VERSION", "COPYRIGHT"\n"; +static Window* testwin; +static ulong testtime[2]; + +static const char version[] = "wistrut-"VERSION", "COPYRIGHT"\n"; + +static void manage(ulong); static void usage(void) { - fatal("usage: %s <window>\n", argv0); + fatal("usage: %s [-HV] <window|class>...\n", argv0); } static int @@ -20,14 +26,32 @@ errfmt(Fmt *f) { return fmtstrcpy(f, ixp_errbuf()); } -void -debug(int flag, const char *fmt, ...) { - va_list ap; - - USED(flag); - va_start(ap, fmt); - vfprint(2, fmt, ap); - va_end(ap); +static void +search_wins(char *pattern) { + ulong *wins; + ulong n, num; + int i; + char **class; + Reprog *regexp; + Window *win; + + regexp = regcomp(pattern); + + num = getprop_ulong(&scr.root, "_NET_CLIENT_LIST", "WINDOW", 0L, &wins, 1024L); + for(i = 0; i < num; i++) { + win = window(wins[i]); + + n = getprop_textlist(win, "WM_CLASS", &class); + bufclear(); + bufprint("%s:%s:%s", + (n > 0 ? class[0] : "<nil>"), + (n > 1 ? class[1] : "<nil>"), + freelater(windowname(win))); + freestringlist(class); + if(regexec(regexp, buffer, nil, 0)) + manage(wins[i]); + } + free(wins); } static Window @@ -43,6 +67,7 @@ findframe(Window *w) { XQueryTree(display, xw, &root, &par, &children, &n); XFree(children); } + ret.type = WWindow; ret.xid = xw; ret.parent = &scr.root; return ret; @@ -62,37 +87,91 @@ getwinsize(Window *win) { Pt(x+border, y+border)); } +static bool +managable(ulong xid) { + ulong *ret; + ulong n; + bool retval; + + n = getprop_ulong(window(xid), "_WMII_STRUT", "WINDOW", 0L, &ret, 1L); + if(n < 0) + retval = true; + else { + if(ret[0] == xid) + retval = ret[0] != testtime[0] || ret[1] != testtime[1]; + else + retval = managable(ret[0]); + } + free(ret); + return retval; +} + +static void +manage(ulong xid) { + Window *frame; + Window *win; + + if(!managable(xid)) + return; + + win = emallocz(sizeof *win); + frame = emalloc(sizeof *frame); + + win->type = WWindow; + win->xid = xid; + *frame = findframe(win); + frame->aux = win; + + getwinsize(frame); + restrut(frame); + sethandler(frame, &handlers); + selectinput(frame, StructureNotifyMask); + + changeprop_ulong(frame, "_WMII_STRUT", "WINDOW", testtime, nelem(testtime)); +} + int main(int argc, char *argv[]) { + ulong win; char *s; fmtinstall('r', errfmt); -extern int fmtevent(Fmt*); fmtinstall('E', fmtevent); ARGBEGIN{ + case 'H': + direction = DHorizontal; + break; + case 'V': + direction = DVertical; + break; + case 'v': + print("%s", version); + return 0; default: usage(); }ARGEND; - s = EARGF(usage()); - if(!getulong(s, &win.xid)) - usage(); - - if(argc) - usage(); - setlocale(LC_CTYPE, ""); initdisplay(); - frame = findframe(&win); - getwinsize(&frame); - restrut(); - sethandler(&frame, &handlers); - selectinput(&frame, StructureNotifyMask); + testwin = createwindow(&scr.root, Rect(0, 0, 1, 1), 0, + InputOnly, nil, 0); + testtime[0] = testwin->xid; + testtime[1] = time(nil); + + while(argc) { + s = ARGF(); + if(getulong(s, &win)) + manage(win); + else + search_wins(s); + } + + changeprop_ulong(testwin, "_WMII_STRUT", "WINDOW", testtime, nelem(testtime)); - event_looprunning = true; + event_looprunning = windowmap.nmemb > 0; event_loop(); XCloseDisplay(display); diff --git a/cmd/strut/win.c b/cmd/strut/win.c @@ -6,14 +6,14 @@ #include "fns.h" void -restrut(void) { +restrut(Window *frame) { enum { Left, Right, Top, Bottom }; Rectangle strut[4]; Rectangle r; - r = frame.r; + r = frame->r; memset(strut, 0, sizeof strut); - if(Dx(r) < Dx(scr.rect)/2) { + if(Dx(r) < Dx(scr.rect)/2 && direction != DVertical) { if(r.min.x <= scr.rect.min.x) { strut[Left] = r; strut[Left].min.x = 0; @@ -25,7 +25,7 @@ restrut(void) { strut[Right].max.x = 0; } } - if(Dy(r) < Dy(scr.rect)/2) { + if(Dy(r) < Dy(scr.rect)/2 && direction != DHorizontal) { if(r.min.y <= scr.rect.min.y) { strut[Top] = r; strut[Top].min.y = 0; @@ -38,9 +38,6 @@ restrut(void) { } } -#define pstrut(name) \ - if(!eqrect(strut[name], ZR)) \ - fprint(2, "strut["#name"] = %R\n", strut[name]) /* Choose the struts which take up the least space. * Not ideal. */ @@ -70,29 +67,31 @@ restrut(void) { } #if 0 +#define pstrut(name) \ + if(!eqrect(strut[name], ZR)) \ + fprint(2, "strut["#name"] = %R\n", strut[name]) pstrut(Left); pstrut(Right); pstrut(Top); pstrut(Bottom); #endif - ewmh_setstrut(&win, strut); + ewmh_setstrut(frame->aux, strut); } static void -config(Window *w, XConfigureEvent *ev) { - - USED(w); +config(Window *frame, XConfigureEvent *ev) { - frame.r = rectaddpt(Rect(0, 0, ev->width, ev->height), - Pt(ev->x+ev->border_width, ev->y+ev->border_width)); - restrut(); + frame->r = rectaddpt(Rect(0, 0, ev->width, ev->height), + Pt(ev->x+ev->border_width, ev->y+ev->border_width)); + restrut(frame); } static void destroy(Window *w, XDestroyWindowEvent *ev) { USED(w, ev); - event_looprunning = false; + sethandler(w, nil); + event_looprunning = windowmap.nmemb > 0; } Handlers handlers = { diff --git a/cmd/wihack.sh b/cmd/wihack.sh @@ -1,4 +1,5 @@ #!/bin/sh -f +unset WMII_HACK_TRANSIENT WMII_HACK_TYPE WMII_HACK_TAGS usage() { echo 1>&2 Usage: \ diff --git a/cmd/wmii/client.c b/cmd/wmii/client.c @@ -718,9 +718,7 @@ client_updatename(Client *c) { c->name[0] = '\0'; - str = getprop_string(&c->w, "_NET_WM_NAME"); - if(str == nil) - str = getprop_string(&c->w, "WM_NAME"); + str = windowname(&c->w); if(str) utflcpy(c->name, str, sizeof c->name); free(str); diff --git a/cmd/wmii/ewmh.c b/cmd/wmii/ewmh.c @@ -21,13 +21,12 @@ static void ewmh_setstate(Client*, Atom, int); void ewmh_init(void) { - WinAttr wa; char myname[] = "wmii"; long win; ewmhwin = createwindow(&scr.root, Rect(0, 0, 1, 1), 0 /*depth*/, - InputOnly, &wa, 0); + InputOnly, nil, 0); win = ewmhwin->xid; changeprop_long(&scr.root, Net("SUPPORTING_WM_CHECK"), "WINDOW", &win, 1); diff --git a/cmd/wmii/layout.c b/cmd/wmii/layout.c @@ -484,7 +484,6 @@ static int tvcol(Frame *f) { Framewin *fw; Window *cwin; - WinAttr wa; Rectangle r; Point pt, pt2; uint button; @@ -502,7 +501,7 @@ tvcol(Frame *f) { r.min.y += fw->grabbox.min.y + Dy(fw->grabbox)/2; r.max.y = r.min.y + 1; - cwin = createwindow(&scr.root, r, 0, InputOnly, &wa, 0); + cwin = createwindow(&scr.root, r, 0, InputOnly, nil, 0); mapwin(cwin); ret = TDone; diff --git a/cmd/wmii/main.c b/cmd/wmii/main.c @@ -43,24 +43,22 @@ scan_wins(void) { uint num; XWindow *wins; XWindowAttributes wa; - XWindow d1, d2; + XWindow root, parent; - if(XQueryTree(display, scr.root.xid, &d1, &d2, &wins, &num)) { + if(XQueryTree(display, scr.root.xid, &root, &parent, &wins, &num)) { for(i = 0; i < num; i++) { - if(!XGetWindowAttributes(display, wins[i], &wa)) - continue; - /* Skip transients. */ - if(wa.override_redirect || XGetTransientForHint(display, wins[i], &d1)) + if(!XGetWindowAttributes(display, wins[i], &wa) || wa.override_redirect) continue; + if(!XGetTransientForHint(display, wins[i], &parent)) if(wa.map_state == IsViewable) client_create(wins[i], &wa); } /* Manage transients. */ for(i = 0; i < num; i++) { - if(!XGetWindowAttributes(display, wins[i], &wa)) + if(!XGetWindowAttributes(display, wins[i], &wa) || wa.override_redirect) continue; - if((XGetTransientForHint(display, wins[i], &d1)) - && (wa.map_state == IsViewable)) + if(XGetTransientForHint(display, wins[i], &parent)) + if(wa.map_state == IsViewable) client_create(wins[i], &wa); } } diff --git a/cmd/wmii/mouse.c b/cmd/wmii/mouse.c @@ -42,13 +42,12 @@ static Handlers chandler = { Window* constraintwin(Rectangle r) { Window *w; - WinAttr wa; - w = createwindow(&scr.root, r, 0, InputOnly, &wa, 0); + w = createwindow(&scr.root, r, 0, InputOnly, nil, 0); if(0) { Window *w2; - w2 = createwindow(&scr.root, r, 0, InputOutput, &wa, 0); + w2 = createwindow(&scr.root, r, 0, InputOutput, nil, 0); selectinput(w2, ExposureMask); w->aux = w2; diff --git a/include/stuff/util.h b/include/stuff/util.h @@ -124,6 +124,7 @@ typedef struct MapEnt MapEnt; struct Map { MapEnt**bucket; uint nhash; + uint nmemb; }; void** hash_get(Map*, const char*, bool create); diff --git a/include/stuff/x11.h b/include/stuff/x11.h @@ -189,6 +189,8 @@ struct Screen { Display *display; Screen scr; +extern struct Map windowmap; +extern struct Map atommap; extern const Point ZP; extern const Rectangle ZR; extern Window* pointerwin; @@ -268,6 +270,7 @@ void ungrabpointer(void); int unmapwin(Window*); void warppointer(Point); Window* window(XWindow); +char* windowname(Window*); long winprotocols(Window*); Atom xatom(char*); void sendmessage(Window*, char*, long, long, long, long, long); diff --git a/lib/libstuff/Makefile b/lib/libstuff/Makefile @@ -141,6 +141,7 @@ OBJ=\ x11/properties/getprop_ulong \ x11/properties/getproperty \ x11/properties/strlistdup \ + x11/properties/windowname \ x11/shape/setshapemask \ x11/text/freefont \ x11/text/labelh \ diff --git a/lib/libstuff/map.c b/lib/libstuff/map.c @@ -1,5 +1,6 @@ /* Written by Kris Maglione */ /* Public domain */ +#include <assert.h> #include <string.h> #include <stuff/util.h> @@ -28,9 +29,10 @@ hash(const char *str) { } static void -insert(MapEnt **e, ulong val, const char *key) { +insert(Map *m, MapEnt **e, ulong val, const char *key) { MapEnt *te; + m->nmemb++; te = emallocz(sizeof *te); te->hash = val; te->key = key; @@ -47,7 +49,7 @@ map_getp(Map *map, ulong val, int create) { if((*e)->hash >= val) break; if(*e == nil || (*e)->hash != val) { if(create) - insert(e, val, nil); + insert(map, e, val, nil); else e = &NM; } @@ -71,7 +73,7 @@ hash_getp(Map *map, const char *str, int create) { break; if(*e == nil || (*e)->hash > h || cmp > 0) if(create) - insert(e, h, str); + insert(map, e, h, str); } return e; } @@ -103,6 +105,7 @@ map_rm(Map *map, ulong val) { te = *e; ret = te->val; *e = te->next; + assert(map->nmemb-- > 0); free(te); } return ret; @@ -119,6 +122,7 @@ hash_rm(Map *map, const char *str) { te = *e; ret = te->val; *e = te->next; + assert(map->nmemb-- > 0); free(te); } return ret; diff --git a/lib/libstuff/x11/properties/windowname.c b/lib/libstuff/x11/properties/windowname.c @@ -0,0 +1,17 @@ +/* Copyright ©2007-2010 Kris Maglione <maglione.k at Gmail> + * See LICENSE file for license details. + */ +#include "../x11.h" + +char* +windowname(Window *w) { + char *str; + + str = getprop_string(w, "_NET_WM_NAME"); + if(str == nil) + str = getprop_string(w, "WM_NAME"); + if(str == nil) + str = estrdup(""); + return str; +} + diff --git a/lib/libstuff/x11/windows/createwindow_visual.c b/lib/libstuff/x11/windows/createwindow_visual.c @@ -8,9 +8,13 @@ createwindow_visual(Window *parent, Rectangle r, int depth, Visual *vis, uint class, WinAttr *wa, int valmask) { Window *w; + WinAttr wa_empty; assert(parent->type == WWindow); + if(wa == nil) + wa = &wa_empty; + w = emallocz(sizeof *w); w->visual = vis; w->type = WWindow; diff --git a/lib/libstuff/x11/x11.h b/lib/libstuff/x11/x11.h @@ -14,8 +14,6 @@ #include <stuff/util.h> #undef pointerwin -extern Map windowmap; -extern Map atommap; extern MapEnt* wbucket[137]; extern MapEnt* abucket[137]; diff --git a/man/Makefile b/man/Makefile @@ -5,7 +5,9 @@ include $(ROOT)/mk/wmii.mk TARG = wmii.1 \ wmiir.1 \ wmii9menu.1\ - wimenu.1 + wihack.1 \ + wimenu.1 \ + wistrut.1 $(TARG): Makefile $(ROOT)/mk/wmii.mk header.t2t diff --git a/man/wihack.1 b/man/wihack.1 @@ -0,0 +1,67 @@ +.TH "WIMENU" 1 "May, 2010" "wmii-@VERSION@" + +.SH NAME +.P +wihack \- The wmii window hack + +.SH SYNOPSIS +.P +wihack \fI[\-transient \fI<window>\fR]\fR \fI[\-type \fI<ewmh window type>\fR]\fR \fI[\-tags \fI<tags>\fR]\fR \fI<program>\fR + +.SH DESCRIPTION +.P +\fBwihack\fR is a program which alters the windows created by an +arbitrary program. It has the name \fBwihack\fR because it is just that: +a hack. It uses LD_PRELOAD to override certain Xlib calls and add +properties to newly created windows. + +.SH ARGUMENTS +.TP +\-transient \fI<window>\fR +Marks created windows as transient for a given \fI<window>\fR. +This causes the new window to open in the floating layer of +the same tags as \fI<window>\fR. +.TP +\-type \fI<ewmh window type>\fR +Sets the EWMH window type of the created window to the type +given. \fBwmii\fR understands the following types: + +.RS 8 +.TP +dialog +Opens in the floating layer. +.TP +dock +.TP +menu +.TP +toolbar +Automatically opens in the floating layer. Does not +have a window border or titlebar. +.TP +splash +Automatically floats and does not automatically +receive focus. +.RS -8 +.TP +\-tags \fI<tags>\fR +The created window opens on the given tags. + +.SH BUGS +.P +It is a hack. + +.P +It doesn't work for setuid programs. + +.P +It doesn't work for non\-Xlib programs. + +.SH SEE ALSO +.P +wmii(1) + + +.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net) +.\" cmdline: txt2tags -o- wihack.man1 + diff --git a/man/wihack.man1 b/man/wihack.man1 @@ -0,0 +1,58 @@ +WIMENU +wmii-@VERSION@ +May, 2010 + +%!includeconf: header.t2t + += NAME = + +wihack - The wmii window hack + += SYNOPSIS = + +wihack [-transient <window>] [-type <ewmh window type>] [-tags <tags>] <program> + += DESCRIPTION = + +`wihack` is a program which alters the windows created by an +arbitrary program. It has the name `wihack` because it is just that: +a hack. It uses LD_PRELOAD to override certain Xlib calls and add +properties to newly created windows. + += ARGUMENTS = + +: -transient <window> + Marks created windows as transient for a given <window>. + This causes the new window to open in the floating layer of + the same tags as <window>. +: -type <ewmh window type> + Sets the EWMH window type of the created window to the type + given. `wmii` understands the following types: + + >> + : dialog + Opens in the floating layer. + : dock + : menu + : toolbar + Automatically opens in the floating layer. Does not + have a window border or titlebar. + : splash + Automatically floats and does not automatically + receive focus. + << +: -tags <tags> + The created window opens on the given tags. +: += BUGS = + +It is a hack. + +It doesn't work for setuid programs. + +It doesn't work for non-Xlib programs. + += SEE ALSO = + +wmii(1) + diff --git a/man/wistrut.1 b/man/wistrut.1 @@ -0,0 +1,69 @@ +.TH "WIMENU" 1 "May, 2010" "wmii-@VERSION@" + +.SH NAME +.P +wistrut \- The wmii EWMH strut manager + +.SH SYNOPSIS +.P +wistrut \fI[\-HV]\fR \fI<window|class>\fR... +.P +wistrut \-v + +.SH DESCRIPTION +.P +\fBwistrut\fR automatically sets EWMH struts on windows for programs +which don't provide such functionality. This allows you to leave +utility windows onscreen without obscuring managed clients. Instead, +whatever part of the screen is occupied by the window will be left +free by wmii, provided it is less than half of the screen width or +height. Struts are automatically updated when the managed windows +are moved or resized, and are only applied if the window is touching +an edge of the screen. + +.P +\fBwistrut\fR may be used with any EWMH compatible window manager. + +.SH ARGUMENTS +.P +All non\-option arguments constitute window IDs or regular +expressions. In the latter case, the any window whose +\fI<name>\fR:\fI<class>\fR:\fI<title>\fR (as used in wmii's colrules and tagrules) +will be managed. + +.TP +\-H + +.RS +Only set horizontal struts. Normally, \fBwistrut\fR locates +struts in the direction of the narrowest dimension of the +window, provided it is touching a screen edge. With this +option set, they will always be allocated on either the left +or right of the screen. Never the top or bottom. +.RE +.TP +\-V + +.RS +Only set vertical struts. See \-H. +.RE +.TP +\-v + +.RS +Display version information. +.RE + +.SH BUGS +.P +There is no way to remove struts from a window other than to move it +away from the edge of the screen and kill \fBwistrut\fR. + +.SH SEE ALSO +.P +wmii(1) + + +.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net) +.\" cmdline: txt2tags -o- wistrut.man1 + diff --git a/man/wistrut.man1 b/man/wistrut.man1 @@ -0,0 +1,55 @@ +WIMENU +wmii-@VERSION@ +May, 2010 + +%!includeconf: header.t2t + += NAME = + +wistrut - The wmii EWMH strut manager + += SYNOPSIS = + +wistrut [-HV] <window|class>... + +wistrut -v + += DESCRIPTION = + +`wistrut` automatically sets EWMH struts on windows for programs +which don't provide such functionality. This allows you to leave +utility windows onscreen without obscuring managed clients. Instead, +whatever part of the screen is occupied by the window will be left +free by wmii, provided it is less than half of the screen width or +height. Struts are automatically updated when the managed windows +are moved or resized, and are only applied if the window is touching +an edge of the screen. + +`wistrut` may be used with any EWMH compatible window manager. + += ARGUMENTS = + +All non-option arguments constitute window IDs or regular +expressions. In the latter case, the any window whose +<name>:<class>:<title> (as used in wmii's colrules and tagrules) +will be managed. + +: -H + Only set horizontal struts. Normally, `wistrut` locates + struts in the direction of the narrowest dimension of the + window, provided it is touching a screen edge. With this + option set, they will always be allocated on either the left + or right of the screen. Never the top or bottom. +: -V + Only set vertical struts. See -H. +: -v + Display version information. + += BUGS = + +There is no way to remove struts from a window other than to move it +away from the edge of the screen and kill `wistrut`. + += SEE ALSO = + +wmii(1) + diff --git a/util/compile b/util/compile @@ -59,7 +59,7 @@ undup() { # GCC is crap. } cat $xtmp | sed "s,^$re,$base&,g; s,\([[:space:]]\)$re,\1$base\2,g" | - egrep -v ': error: .Each undeclared identifier|: error: for each function it appears|is dangerous, better use|is almost always misused|: In function |: At top level:|support .long long.|use of C99 long long|ISO C forbids conversion|warning:.*warn_unused_result' | + egrep -iv ': (error|note): .?Each undeclared identifier|: error: for each function it appears|is dangerous, better use|is almost always misused|: In function |: At top level:|support .long long.|use of C99 long long|ISO C forbids conversion|warning:.*warn_unused_result' | sed 's/ .first use in this function.$//; s/\"\([^\"][^\"]*\)\", line \([0-9][0-9]*\)/\1:\2/g' | awk '$1 == "warning:"{t=$2" "$1; sub(/^[^ ]+ [^ ]+ /, ""); $0 = t" "$0}; //' | awk '{sub(/\[/, ": [", $1); print}' |