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

This commit is contained in:
Kris Maglione 2010-05-24 15:17:09 -04:00
parent 9adfeea6c2
commit e3fdbdb548
24 changed files with 421 additions and 69 deletions

View File

@ -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 \

View File

@ -11,8 +11,8 @@
# define EXTERN extern
#endif
enum { DAuto, DHorizontal, DVertical };
EXTERN Handlers handlers;
EXTERN Window win;
EXTERN Window frame;
EXTERN int direction;

View File

@ -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]);

View File

@ -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;
static void
search_wins(char *pattern) {
ulong *wins;
ulong n, num;
int i;
char **class;
Reprog *regexp;
Window *win;
USED(flag);
va_start(ap, fmt);
vfprint(2, fmt, ap);
va_end(ap);
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);
event_looprunning = true;
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 = windowmap.nmemb > 0;
event_loop();
XCloseDisplay(display);

View File

@ -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) {
config(Window *frame, XConfigureEvent *ev) {
USED(w);
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 = {

View File

@ -1,4 +1,5 @@
#!/bin/sh -f
unset WMII_HACK_TRANSIENT WMII_HACK_TYPE WMII_HACK_TAGS
usage() {
echo 1>&2 Usage: \

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;

View File

@ -124,6 +124,7 @@ typedef struct MapEnt MapEnt;
struct Map {
MapEnt**bucket;
uint nhash;
uint nmemb;
};
void** hash_get(Map*, const char*, bool create);

View File

@ -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);

View File

@ -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 \

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -14,8 +14,6 @@
#include <stuff/util.h>
#undef pointerwin
extern Map windowmap;
extern Map atommap;
extern MapEnt* wbucket[137];
extern MapEnt* abucket[137];

View File

@ -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

67
man/wihack.1 Normal file
View File

@ -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

58
man/wihack.man1 Normal file
View File

@ -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)

69
man/wistrut.1 Normal file
View File

@ -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

55
man/wistrut.man1 Normal file
View File

@ -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)

View File

@ -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}' |