wmii

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

commit ff4fc9cee749084594914252b6b83a9c1456e39c
parent fa4beb5aa8e2f4a9545444ff5a725ba8976447bc
Author: Kris Maglione <kris@suckless.org>
Date:   Fri, 11 Jun 2010 04:18:40 -0400

Require that clients be given permission to activate themselves.

Diffstat:
alternative_wmiircs/plan9port/wmiirc | 5+++++
alternative_wmiircs/python/wmiirc.py | 9+++++++--
cmd/wmii/client.c | 115++++++++++++++++++++++++-------------------------------------------------------
cmd/wmii/column.c | 75+++++++++++++++++++++++++++++++--------------------------------------------
cmd/wmii/dat.h | 23++++++++++++++---------
cmd/wmii/debug.h | 4++--
cmd/wmii/ewmh.c | 36++++++++++++++++++++++++++++++------
cmd/wmii/fns.h | 5+++--
cmd/wmii/main.c | 10+++++-----
cmd/wmii/message.c | 238+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
cmd/wmii/rule.c | 2+-
include/stuff/util.h | 1+
include/stuff/x11.h | 2++
lib/libstuff/Makefile | 1+
lib/libstuff/fmt/fmtbuf.c | 15+++++++++++++++
man/wmii.1 | 34+++++++++++++++++++++++++++-------
man/wmii.man1 | 24+++++++++++++++++++-----
rc/wmiirc.sh | 30++++++++++++++++++------------
18 files changed, 363 insertions(+), 266 deletions(-)

diff --git a/alternative_wmiircs/plan9port/wmiirc b/alternative_wmiircs/plan9port/wmiirc @@ -47,8 +47,13 @@ wmiir write /colrules <<! # Tagging Rules wmiir write /rules <<! + # Apps with system tray icons like to their main windows + # Give them permission. + /^Pidgin:/ allow=+activate + # MPlayer and VLC don't float by default, but should. /MPlayer|VLC/ floating=on + # ROX puts all of its windows in the same group, so they open # with the same tags. Disable grouping for ROX Filer. /^ROX-Filer:/ group=0 diff --git a/alternative_wmiircs/python/wmiirc.py b/alternative_wmiircs/python/wmiirc.py @@ -60,11 +60,16 @@ def time(self): return wmii.cache['focuscolors'], datetime.datetime.now().strftime('%c') wmii.rules = ( + # Apps with system tray icons like to their main windows + # Give them permission. + (ur'^Pidgin:' dict(allow='+activate')), + # MPlayer and VLC don't float by default, but should. - (ur'MPlayer|VLC', dict(floating=True)), + (ur'MPlayer|VLC', dict(floating=True)), + # ROX puts all of its windows in the same group, so they open # with the same tags. Disable grouping for ROX Filer. - (ur'^ROX-Filer:', dict(group=0)), + (ur'^ROX-Filer:', dict(group=0)), ) def unresponsive_client(client): diff --git a/cmd/wmii/client.c b/cmd/wmii/client.c @@ -1111,103 +1111,58 @@ client_extratags(Client *c) { bool client_applytags(Client *c, const char *tags) { Fmt fmt; - uint i, j, k, n; - bool add, found; - char buf[512], last; + uint i, j, k; + char buf[512]; char *toks[32]; char **p; char *cur, *s; + int add, old; buf[0] = 0; - - for(n = 0; tags[n]; n++) - if(!isspace(tags[n])) - break; - - if(tags[n] == '+' || tags[n] == '-' || tags[n] == '\0') + if(memchr("+-^", tags[0], 4)) utflcpy(buf, c->tags, sizeof c->tags); else { refree(&c->tagre); refree(&c->tagvre); } - strlcat(buf, &tags[n], sizeof buf); - - n = 0; - add = true; - if(buf[0] == '+') - n++; - else if(buf[0] == '-') { - n++; - add = false; - } - - found = false; + strlcat(buf, tags, sizeof buf); j = 0; - while(buf[n] && n < sizeof buf && j < 32) { + s = buf; + old = '+'; + while((cur = mask(&s, &add, &old))) { /* Check for regex. */ - if(buf[n] == '/') { - for(i=n+1; i < sizeof buf - 1; i++) - if(buf[i] == '/') break; - if(buf[i] == '/') { - i++; - if(buf[i] == '+' - || buf[i] == '-' - || buf[i] == '\0') { /* Don't be lenient */ - buf[i-1] = '\0'; - if(add) - reinit(&c->tagre, buf+n+1); - else - reinit(&c->tagvre, buf+n+1); - last = buf[i]; - buf[i] = '\0'; - - found = true; - goto next; - } - } + if(cur[0] == '/') { + cur++; + *strchr(cur, '/') = '\0'; + if(add == '+') + reinit(&c->tagre, cur); + else if(add == '-') + reinit(&c->tagvre, cur); } - for(i = n; i < sizeof buf - 1; i++) - if(buf[i] == '+' - || buf[i] == '-' - || buf[i] == '\0') - break; - last = buf[i]; - buf[i] = '\0'; - - trim(buf+n, " \t/"); - - cur = nil; - if(!strcmp(buf+n, "~")) + trim(cur, " \t\r\n"); + if(!strcmp(cur, "~")) c->floating = add ? On : Never; - else - if(!strcmp(buf+n, "!") || !strcmp(buf+n, "sel")) - cur = selview->name; - else - if(!Mbsearch(buf+n, badtags, bsstrcmp)) - cur = buf+n; - - if(cur && j < nelem(toks)-1) { - if(add) { - found = true; - toks[j++] = cur; - }else { - for(i = 0, k = 0; i < j; i++) - if(strcmp(toks[i], cur)) - toks[k++] = toks[i]; - j = k; + else { + if(!strcmp(cur, "!") || !strcmp(cur, "sel")) + cur = selview->name; + else if(Mbsearch(cur, badtags, bsstrcmp)) + continue; + + if(j < nelem(toks)-1) { + if(add == '^') + add = bsearch(cur, toks, j, sizeof *toks, bsstrcmp) ? '-' : '+'; + if(add == '+') + toks[j++] = cur; + else { + for(i = 0, k = 0; i < j; i++) + if(strcmp(toks[i], cur)) + toks[k++] = toks[i]; + j = k; + } } } - - next: - n = i + 1; - if(last == '+') - add = true; - if(last == '-') - add = false; - if(last == '\0') - break; } toks[j] = nil; @@ -1241,6 +1196,6 @@ client_applytags(Client *c, const char *tags) { p = comm(~0, c->retags, toks); client_setviews(c, p); free(p); - return found; + return true; } diff --git a/cmd/wmii/column.c b/cmd/wmii/column.c @@ -17,8 +17,8 @@ char *modes[] = { bool column_setmode(Area *a, const char *mode) { - char *str, *tok, *orig; - char add, old; + char *str, *tok; + int add, old; /* * The mapping between the current internal @@ -27,49 +27,36 @@ column_setmode(Area *a, const char *mode) { * change. */ - orig = strdup(mode); - str = orig; - old = '\0'; - while(*(tok = str)) { - add = old; - while((old=*str) && !strchr("+-^", old)) - str++; - *str = '\0'; - if(str > tok) { - if(!strcmp(tok, "max")) { - if(add == '\0' || add == '+') - a->max = true; - else if(add == '-') - a->max = false; - else - a->max = !a->max; - }else - if(!strcmp(tok, "stack")) { - if(add == '\0' || add == '+') - a->mode = Colstack; - else if(add == '-') - a->mode = Coldefault; - else - a->mode = a->mode == Colstack ? Coldefault : Colstack; - }else - if(!strcmp(tok, "default")) { - if(add == '\0' || add == '+') { - a->mode = Coldefault; - column_arrange(a, true); - }else if(add == '-') - a->mode = Colstack; - else - a->mode = a->mode == Coldefault ? Colstack : Coldefault; - }else { - free(orig); - return false; - } - } - if(old) - str++; - + str = freelater(estrdup(mode)); + old = '+'; + while((tok = mask(&str, &add, &old))) { + if(!strcmp(tok, "max")) { + if(add == '\0' || add == '+') + a->max = true; + else if(add == '-') + a->max = false; + else + a->max = !a->max; + }else + if(!strcmp(tok, "stack")) { + if(add == '\0' || add == '+') + a->mode = Colstack; + else if(add == '-') + a->mode = Coldefault; + else + a->mode = a->mode == Colstack ? Coldefault : Colstack; + }else + if(!strcmp(tok, "default")) { + if(add == '\0' || add == '+') { + a->mode = Coldefault; + column_arrange(a, true); + }else if(add == '-') + a->mode = Colstack; + else + a->mode = a->mode == Coldefault ? Colstack : Coldefault; + }else + return false; } - free(orig); return true; } diff --git a/cmd/wmii/dat.h b/cmd/wmii/dat.h @@ -43,6 +43,10 @@ enum { UrgClient, }; +enum ClientPermission { + PermActivate = 1<<0, +}; + enum { SourceUnknown, SourceClient, @@ -169,25 +173,26 @@ struct Client { Group* group; Strut* strut; Cursor cursor; - Rectangle r; Rectangle configr; + Rectangle r; char** retags; - char name[256]; char class[256]; - char tags[256]; + char name[256]; char props[512]; + char tags[256]; + long permission; long proto; - uint border; - int pid; + int border; int dead; - int fullscreen; int floating; - bool fixedsize; - bool urgent; + int fullscreen; + int pid; bool borderless; - bool titleless; + bool fixedsize; bool nofocus; bool noinput; + bool titleless; + bool urgent; }; struct Divide { diff --git a/cmd/wmii/debug.h b/cmd/wmii/debug.h @@ -20,5 +20,5 @@ void dwrite(int, void*, int, bool); bool setdebug(int); void vdebug(int, const char*, va_list); -int debugflag; -int debugfile; +long debugflag; +long debugfile; diff --git a/cmd/wmii/ewmh.c b/cmd/wmii/ewmh.c @@ -50,6 +50,8 @@ ewmh_init(void) { NET("WM_PID"), NET("WM_STRUT"), NET("WM_STRUT_PARTIAL"), + /* Set this so clients don't update Net("USER_TIME") */ + NET("USER_TIME_WINDOW"), /* States */ NET("WM_STATE"), STATE("DEMANDS_ATTENTION"), @@ -179,6 +181,25 @@ ewmh_destroyclient(Client *c) { free(c->strut); } +#ifdef notdef +static ulong +usertime(Window *w) { + long *l; + long ret; + + ret = 0; + if(getprop_long(w, Net("WM_USER_TIME_WINDOW"), "CARDINAL", 0, &l, 1)) { + w = window(*l); + free(l); + } + if(getprop_long(w, Net("WM_USER_TIME"), "CARDINAL", 0, &l, 1)) { + ret = *l; + free(l); + } + return ret; +} +#endif + static bool event_client_clientmessage(Window *w, void *aux, XClientMessageEvent *e) { Client *c; @@ -215,11 +236,13 @@ event_client_clientmessage(Window *w, void *aux, XClientMessageEvent *e) { if(msg == NET("ACTIVE_WINDOW")) { if(e->format != 32) return false; + Dprint(DEwmh, "\tsource: %uld\n", l[0]); + Dprint(DEwmh, "\ttimestamp: %,uld\n", l[1]); + Dprint(DEwmh, "\tactive: %#ulx\n", l[2]); + Dprint(DEwmh, "\twindow: %#ulx\n", e->window); + Dprint(DEwmh, "\tclient: %C\n", c); - Dprint(DEwmh, "\tsource: %ld\n", l[0]); - Dprint(DEwmh, "\twindow: %#ulx\n", e->window); - Dprint(DEwmh, "\tclient: %C\n", c); - if(l[0] == SourceClient && abs(event_xtime - l[1]) > 5000) + if(l[0] == SourceClient && !(c->permission & PermActivate)) return false; if(l[0] == SourceClient || l[0] == SourcePager) focus(c, true); @@ -421,7 +444,9 @@ event_root_clientmessage(Window *w, void *aux, XClientMessageEvent *e) { l = (ulong*)e->data.l; msg = e->message_type; - Dprint(DEwmh, "ClientMessage: %A\n", msg); + Debug(DEwmh) + if(msg != xatom("WM_PROTOCOLS") && l[0] != NET("WM_PING")) + Dprint(DEwmh, "ClientMessage: %A\n", msg); if(msg == NET("CURRENT_DESKTOP")) { if(e->format != 32) @@ -447,7 +472,6 @@ event_root_clientmessage(Window *w, void *aux, XClientMessageEvent *e) { c->w.ewmh.lag = (c->w.ewmh.ping & 0xffffffff) - (l[1] & 0xffffffff); if(i == false) frame_draw(c->sel); - Dprint(DEwmh, "\twindow=%W lag=%,uld\n", &c->w, c->w.ewmh.lag); return false; } return false; diff --git a/cmd/wmii/fns.h b/cmd/wmii/fns.h @@ -203,12 +203,13 @@ void init_screens(void); void spawn_command(const char*); /* message.c */ +char* mask(char**, int*, int*); char* message_client(Client*, IxpMsg*); char* message_root(void*, IxpMsg*); char* message_view(View*, IxpMsg*); -char* msg_debug(IxpMsg*); +void msg_debug(char*); void msg_eatrunes(IxpMsg*, int (*)(Rune), int); -char* msg_getword(IxpMsg*); +char* msg_getword(IxpMsg*, char*); void msg_parsecolors(IxpMsg*, CTuple*); char* msg_selectarea(Area*, IxpMsg*); char* msg_sendclient(View*, IxpMsg*, bool swap); diff --git a/cmd/wmii/main.c b/cmd/wmii/main.c @@ -330,9 +330,8 @@ printfcall(IxpFcall *f) { int main(int argc, char *argv[]) { - IxpMsg m; char **oargv; - char *wmiirc, *s; + char *wmiirc; int i; setlocale(LC_CTYPE, ""); @@ -356,9 +355,10 @@ main(int argc, char *argv[]) { lprint(1, "%s", version); exit(0); case 'D': - s = EARGF(usage()); - m = ixp_message(s, strlen(s), 0); - msg_debug(&m); + if(waserror()) + fatal("parsing debug flags: %r"); + msg_debug(EARGF(usage())); + poperror(); break; default: usage(); diff --git a/cmd/wmii/message.c b/cmd/wmii/message.c @@ -24,6 +24,7 @@ static char /* Edit |sort Edit |sed 's/"([^"]+)"/L\1/g' | tr 'a-z' 'A-Z' */ enum { + LALLOW, LBAR, LBORDER, LCLIENT, @@ -62,6 +63,7 @@ enum { LTILDE, }; char *symtab[] = { + "allow", "bar", "border", "client", @@ -100,6 +102,9 @@ char *symtab[] = { "~", }; +static char* barpostab[] = { + "bottom", "top", +}; char* debugtab[] = { "9p", "dnd", @@ -108,16 +113,13 @@ char* debugtab[] = { "focus", "generic", "stack", + nil }; - -static char* barpostab[] = { - "bottom", - "top", +static char* permtab[] = { + "activate", nil }; static char* incmodetab[] = { - "ignore", - "show", - "squeeze", + "ignore", "show", "squeeze", }; static char* floatingtab[] = { "never", "off", "on", "always" @@ -204,7 +206,7 @@ static int getdirection(IxpMsg *m) { int i; - switch(i = getsym(msg_getword(m))) { + switch(i = getsym(msg_getword(m, 0))) { case LLEFT: case LRIGHT: case LUP: @@ -249,7 +251,7 @@ msg_eatrunes(IxpMsg *m, int (*p)(Rune), int val) { } char* -msg_getword(IxpMsg *m) { +msg_getword(IxpMsg *m, char *errmsg) { char *ret; Rune r; int n; @@ -271,10 +273,102 @@ msg_getword(IxpMsg *m) { if(ret[1] == '\\' || ret[1] == '#') ret++; if(*ret == '\0') - return nil; + ret = nil; + if(ret == nil && errmsg) + error(errmsg); return ret; } +typedef struct Mask Mask; +struct Mask { + long* mask; + char** table; +}; + +static int +Mfmt(Fmt *f) { + Mask m; + int i; + + m = va_arg(f->args, Mask); + for(i=0; m.table[i]; i++) + if(*m.mask & (1<<i)) { + if(*m.mask & ((1<<i)-1)) + fmtstrcpy(f, "+"); + if(fmtstrcpy(f, m.table[i])) + return -1; + } + return 0; +} + +char* +mask(char **s, int *add, int *old) { + static char seps[] = "+-^"; + char *p, *q; + +again: + p = *s; + if(*old == '\0') + return nil; + *add = *old; + + if(*p == '/') { + /* Check for regex. */ + if(!(q = strchr(p+1, '/'))) + goto fail; + if(*q++ != '/' || !memchr(seps, (*old=*q), sizeof seps)) + goto fail; + } + else { + for(q=p; (*old=*q) && !strchr(seps, *q);) + q++; + if(memchr(p, '/', q-p)) + goto fail; + } + + *q++ = '\0'; + *s = q; + if(p + 1 == q) + goto again; + return p; +fail: + while((*old=*q) && !strchr(seps, *q)) + q++; + goto again; +} + +static void +unmask(Mask m, char *s) { + char *opt; + int add, old, i, n; + long newmask; + + if(s == nil) + s = ""; + for(n=0; m.table[n]; n++) + ; + newmask = memchr("+-^", s[0], 3) ? *m.mask : 0L; + + old = '+'; + while((opt = mask(&s, &add, &old))) { + i = _bsearch(opt, m.table, n); + if(i == -1) + error(Ebadvalue); + else if(add = '^') + newmask ^= 1<<i; + else if(add == '+') + newmask |= 1<<i; + else if(add == '-') + newmask &= ~(1<<i); + } + *m.mask = newmask; +} + +void +msg_debug(char *s) { + unmask((Mask){&debugflag, debugtab}, s); +} + static Client* strclient(View *v, char *s) { Client *c; @@ -362,17 +456,17 @@ getframe(View *v, int scrn, IxpMsg *m) { char *s; ulong l; - s = msg_getword(m); - if(!s || !strcmp(s, "client")) - f = client_viewframe(strclient(v, msg_getword(m)), + s = msg_getword(m, Ebadvalue); + if(!strcmp(s, "client")) + f = client_viewframe(strclient(v, msg_getword(m, Ebadvalue)), v); else { /* XXX: Multihead */ a = strarea(v, scrn, s); - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); f = nil; - if(s && !strcmp(s, "sel")) + if(!strcmp(s, "sel")) f = a->sel; else { l = msg_getulong(s); @@ -389,6 +483,7 @@ char* readctl_client(Client *c) { bufclear(); bufprint("%#C\n", c); + bufprint("allow %M\n", (Mask){&c->permission, permtab}); bufprint("floating %s\n", floatingtab[c->floating + 1]); if(c->fullscreen >= 0) bufprint("fullscreen %d\n", c->fullscreen); @@ -407,7 +502,7 @@ message_client(Client *c, IxpMsg *m) { char *s; long l; - s = msg_getword(m); + s = msg_getword(m, Ebadcmd); /* * Toggle ::= on @@ -423,11 +518,14 @@ message_client(Client *c, IxpMsg *m) { */ switch(getsym(s)) { + case LALLOW: + unmask((Mask){&c->permission, permtab}, msg_getword(m, 0)); + break; case LFLOATING: - c->floating = -1 + _lsearch(msg_getword(m), floatingtab, nelem(floatingtab)); + c->floating = -1 + _lsearch(msg_getword(m, Ebadvalue), floatingtab, nelem(floatingtab)); break; case LFULLSCREEN: - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); if(getlong(s, &l)) fullscreen(c, On, l); else @@ -435,7 +533,7 @@ message_client(Client *c, IxpMsg *m) { break; case LGROUP: group_remove(c); - c->w.hints->group = msg_getulong(msg_getword(m)); + c->w.hints->group = msg_getulong(msg_getword(m, Ebadvalue)); if(c->w.hints->group) group_init(c); break; @@ -449,7 +547,7 @@ message_client(Client *c, IxpMsg *m) { client_applytags(c, m->pos); break; case LURGENT: - client_seturgent(c, gettoggle(msg_getword(m)), UrgManager); + client_seturgent(c, gettoggle(msg_getword(m, Ebadvalue)), UrgManager); break; default: error(Ebadcmd); @@ -466,7 +564,7 @@ message_root(void *p, IxpMsg *m) { USED(p); ret = nil; - s = msg_getword(m); + s = msg_getword(m, 0); if(s == nil) return nil; @@ -477,21 +575,21 @@ message_root(void *p, IxpMsg *m) { switch(getsym(s)) { case LBAR: /* bar on? <"top" | "bottom"> */ - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); if(!strcmp(s, "on")) - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); setdef(&screen->barpos, s, barpostab, nelem(barpostab)); view_update(selview); break; case LBORDER: - def.border = msg_getulong(msg_getword(m));; + def.border = msg_getulong(msg_getword(m, 0));; view_update(selview); break; case LCOLMODE: - setdef(&def.colmode, msg_getword(m), modes, Collast); + setdef(&def.colmode, msg_getword(m, 0), modes, Collast); break; case LDEBUG: - ret = msg_debug(m); + msg_debug(msg_getword(m, 0)); break; case LEXEC: execstr = strdup(m->pos); @@ -516,10 +614,10 @@ message_root(void *p, IxpMsg *m) { view_update(selview); break; case LFONTPAD: - if(!getint(msg_getword(m), &def.font->pad.min.x) || - !getint(msg_getword(m), &def.font->pad.max.x) || - !getint(msg_getword(m), &def.font->pad.max.y) || - !getint(msg_getword(m), &def.font->pad.min.y)) + if(!getint(msg_getword(m, 0), &def.font->pad.min.x) || + !getint(msg_getword(m, 0), &def.font->pad.max.x) || + !getint(msg_getword(m, 0), &def.font->pad.max.y) || + !getint(msg_getword(m, 0), &def.font->pad.min.y)) ret = "invalid rectangle"; else { for(n=0; n < nscreens; n++) @@ -528,7 +626,7 @@ message_root(void *p, IxpMsg *m) { } break; case LGRABMOD: - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); if(!parsekey(s, &i, nil) || i == 0) return Ebadvalue; @@ -536,7 +634,7 @@ message_root(void *p, IxpMsg *m) { def.mod = i; break; case LINCMODE: - setdef(&def.incmode, msg_getword(m), incmodetab, nelem(incmodetab)); + setdef(&def.incmode, msg_getword(m, 0), incmodetab, nelem(incmodetab)); view_update(selview); break; case LNORMCOLORS: @@ -558,33 +656,17 @@ message_root(void *p, IxpMsg *m) { return ret; } -static void -printdebug(int mask) { - int i, j; - - for(i=0, j=0; i < nelem(debugtab); i++) - if(mask & (1<<i)) { - if(j++ > 0) bufprint(" "); - bufprint("%s", debugtab[i]); - } -} - char* readctl_root(void) { + fmtinstall('M', Mfmt); bufclear(); bufprint("bar on %s\n", barpostab[screen->barpos]); bufprint("border %d\n", def.border); bufprint("colmode %s\n", modes[def.colmode]); - if(debugflag) { - bufprint("debug "); - printdebug(debugflag); - bufprint("\n"); - } - if(debugfile) { - bufprint("debugfile "); - printdebug(debugfile); - bufprint("\n"); - } + if(debugflag) + bufprint("debug %M\n", (Mask){&debugflag, debugtab}); + if(debugfile) + bufprint("debugfile %M", (Mask){&debugfile, debugtab}); bufprint("focuscolors %s\n", def.focuscolor.colstr); bufprint("font %s\n", def.font->name); bufprint("fontpad %d %d %d %d\n", def.font->pad.min.x, def.font->pad.max.x, @@ -601,7 +683,7 @@ message_view(View *v, IxpMsg *m) { Area *a; char *s; - s = msg_getword(m); + s = msg_getword(m, 0); if(s == nil) return nil; @@ -648,11 +730,11 @@ message_view(View *v, IxpMsg *m) { switch(getsym(s)) { case LCOLMODE: - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); a = strarea(v, screen->idx, s); - s = msg_getword(m); - if(s == nil || !column_setmode(a, s)) + s = msg_getword(m, Ebadvalue); + if(!column_setmode(a, s)) return Ebadvalue; column_arrange(a, false); @@ -699,38 +781,12 @@ readctl_view(View *v) { return buffer; } -char* -msg_debug(IxpMsg *m) { - char *opt; - int d; - char add; - - bufclear(); - while((opt = msg_getword(m))) { - add = '+'; - if(opt[0] == '+' || opt[0] == '-') - add = *opt++; - d = _bsearch(opt, debugtab, nelem(debugtab)); - if(d == -1) { - bufprint(", %s", opt); - continue; - } - if(add == '+') - debugflag |= 1<<d; - else - debugflag &= ~(1<<d); - } - if(buffer[0] != '\0') - return sxprint("Bad debug options: %s", buffer+2); - return nil; -} - static void getamt(IxpMsg *m, Point *amt) { char *s, *p; long l; - s = msg_getword(m); + s = msg_getword(m, 0); if(s) { p = strend(s, 2); if(!strcmp(p, "px")) { @@ -863,7 +919,7 @@ msg_selectarea(Area *a, IxpMsg *m) { int sym; v = a->view; - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); sym = getsym(s); switch(sym) { @@ -889,7 +945,8 @@ msg_selectarea(Area *a, IxpMsg *m) { ap = strarea(v, a->screen, s); if(ap->floating) return Ebadvalue; - if((s = msg_getword(m))) { + + if((s = msg_getword(m, 0))) { i = msg_getulong(s); for(f = ap->frame; f; f = f->anext) if(--i == 0) break; @@ -917,14 +974,14 @@ msg_selectframe(Area *a, IxpMsg *m, int sym) { stack = false; if(sym == LUP || sym == LDOWN) - if((s = msg_getword(m))) + if((s = msg_getword(m, 0))) if(!strcmp(s, "stack")) stack = true; else return Ebadvalue; if(sym == LCLIENT) { - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); i = msg_getulong(s); c = win2client(i); if(c == nil) @@ -985,8 +1042,7 @@ msg_sendclient(View *v, IxpMsg *m, bool swap) { char *s; int sym; - s = msg_getword(m); - c = strclient(v, s); + c = strclient(v, msg_getword(m, 0)); f = client_viewframe(c, v); if(f == nil) return Ebadvalue; @@ -994,7 +1050,7 @@ msg_sendclient(View *v, IxpMsg *m, bool swap) { a = f->area; to = nil; - s = msg_getword(m); + s = msg_getword(m, Ebadvalue); sym = getsym(s); /* FIXME: Should use a helper function. */ diff --git a/cmd/wmii/rule.c b/cmd/wmii/rule.c @@ -88,7 +88,7 @@ value: valuebuf.end = valuebuf.pos; valuebuf.pos = valuebuf.data; rvp = &r->values; - while((w = msg_getword(&valuebuf))) { + while((w = msg_getword(&valuebuf, 0))) { free(r->value); r->value = estrdup(w); if(strchr(w, '=')) { diff --git a/include/stuff/util.h b/include/stuff/util.h @@ -56,6 +56,7 @@ void* erealloc(void*, uint); char* estrdup(const char*); char* estrndup(const char*, uint); void fatal(const char*, ...); +Fmt fmtbuf(char*, int); void* freelater(void*); int getbase(const char**, long*); bool getint(const char*, int*); diff --git a/include/stuff/x11.h b/include/stuff/x11.h @@ -4,6 +4,7 @@ #define Window XWindow #define Font XFont #define Screen XScreen +#define Mask XMask #include <stuff/geom.h> #include <X11/Xlib.h> #include <X11/Xutil.h> @@ -16,6 +17,7 @@ #undef Window #undef Font #undef Screen +#undef Mask enum FontType { FX11 = 1, diff --git a/lib/libstuff/Makefile b/lib/libstuff/Makefile @@ -36,6 +36,7 @@ OBJ=\ event/xtime \ fmt/blprint \ fmt/bvlprint \ + fmt/fmtbuf \ fmt/localefmt \ fmt/localelen \ fmt/lprint \ diff --git a/lib/libstuff/fmt/fmtbuf.c b/lib/libstuff/fmt/fmtbuf.c @@ -0,0 +1,15 @@ +#include "fmtdef.h" + +Fmt +fmtbuf(char *buf, int len) { + Fmt f; + + f.runes = 0; + f.start = buf; + f.to = buf; + f.stop = buf + len - 1; + f.flush = 0; + f.farg = nil; + f.nfmt = 0; + return f; +} diff --git a/man/wmii.1 b/man/wmii.1 @@ -384,9 +384,28 @@ of the client. The following commands may be written to it: .RS 8 .TP -floating \fI<on | off | toggle>\fR +allow \fI<flags>\fR +The set of unusual actions the client is allowed to +perform, in the same format as the tag set. +.RS 8 +.TP +activate +The client is allowed to activate +itself – that is, focus its window and, +as the case may require, uncollapse it +and select a tag it resides on. This +flag must be set on a client if you wish +it able to activate itself from the +system tray. +.RS -8 +.TP +floating \fI<on | off | always | never>\fR Defines whether this client is likely to float when -attached to a new view. +attached to a new view. Ordinarilly, the value +changes automatically whenever the window is +moved between the floating and managed layers. +However, setting a value of \fIalways\fR or \fInever\fR +overrides this behavior. .TP fullscreen \fI<on | off | toggle>\fR Sets the client's fullscreen state. @@ -428,11 +447,12 @@ Returns a clients class and label as: .TP tags Set or read a client's tags. Tags are separated by -\fB+\fR or \fB\-\fR. Tags beginning with \fB+\fR are -added, while those beginning with \fB\-\fR are removed. -If the tag string written begins with \fB+\fR or -\fB\-\fR, the written tags are added to or removed from -the client's set, otherwise, the set is overwritten. +\fB+\fR, \fB\-\fR, or \fB^\fR. Tags beginning with \fB+\fR are +added, while those beginning with \fB\-\fR are removed and +those beginning with \fB^\fR are toggled. If the tag +string written begins with \fB+\fR, \fB^\fR, or \fB\-\fR, the +written tags are added to or removed from the client's +set, otherwise the set is overwritten. .SS The /tag/ Hierarchy diff --git a/man/wmii.man1 b/man/wmii.man1 @@ -332,6 +332,19 @@ represents the currently selected client. of the client. The following commands may be written to it: >> + : allow <flags> + The set of unusual actions the client is allowed to + perform, in the same format as the tag set. + >> + : activate + The client is allowed to activate + itself – that is, focus its window and, + as the case may require, uncollapse it + and select a tag it resides on. This + flag must be set on a client if you wish + it able to activate itself from the + system tray. + << : floating <on | off | always | never> Defines whether this client is likely to float when attached to a new view. Ordinarilly, the value @@ -370,11 +383,12 @@ represents the currently selected client. <instance>:<class>:<label>. : tags Set or read a client's tags. Tags are separated by - **+** or **-**. Tags beginning with **+** are - added, while those beginning with **-** are removed. - If the tag string written begins with **+** or - **-**, the written tags are added to or removed from - the client's set, otherwise, the set is overwritten. + **+**, **-**, or **^**. Tags beginning with **+** are + added, while those beginning with **-** are removed and + those beginning with **^** are toggled. If the tag + string written begins with **+**, **^**, or **-**, the + written tags are added to or removed from the client's + set, otherwise the set is overwritten. : == The /tag/ Hierarchy == diff --git a/rc/wmiirc.sh b/rc/wmiirc.sh @@ -25,18 +25,19 @@ export WMII_FONT='-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*' set -- $(echo $WMII_NORMCOLORS $WMII_FOCUSCOLORS) export WMII_TERM="@TERMINAL@" -if ! test -d "${WMII_CONFPATH%%:*}"; then - mkdir "${WMII_CONFPATH%%:*}" - res=$(wihack -type DIALOG xmessage -nearmouse -buttons Windows,Alt -print -fn $WMII_FONT \ - "Welcome to wmii,$wi_newline$wi_newline" \ - "Most of wmii's default key bindings make use of the$wi_newline" \ - "Windows key, or equivalent. For keyboards lacking such$wi_newline" \ - "a key, many users change this to the Alt key.$wi_newline$wi_newline" \ - "Which would you prefer?") - [ "$res" = "Alt" ] && MODKEY=Mod1 - echo "MODKEY=$MODKEY" >"${WMII_CONFPATH%%:*}/wmiirc_local" - chmod +x "${WMII_CONFPATH%%:*}/wmiirc_local" -fi +# Ask about MODKEY on first run + if ! test -d "${WMII_CONFPATH%%:*}"; then + mkdir "${WMII_CONFPATH%%:*}" + res=$(wihack -type DIALOG xmessage -nearmouse -buttons Windows,Alt -print -fn $WMII_FONT \ + "Welcome to wmii,$wi_newline$wi_newline" \ + "Most of wmii's default key bindings make use of the$wi_newline" \ + "Windows key, or equivalent. For keyboards lacking such$wi_newline" \ + "a key, many users change this to the Alt key.$wi_newline$wi_newline" \ + "Which would you prefer?") + [ "$res" = "Alt" ] && MODKEY=Mod1 + echo "MODKEY=$MODKEY" >"${WMII_CONFPATH%%:*}/wmiirc_local" + chmod +x "${WMII_CONFPATH%%:*}/wmiirc_local" + fi # Menu history hist="${WMII_CONFPATH%%:*}/history" @@ -50,8 +51,13 @@ wmiir write /colrules <<! # Tagging Rules wmiir write /rules <<! + # Apps with system tray icons like to their main windows + # Give them permission. + /^Pidgin:/ allow=+activate + # MPlayer and VLC don't float by default, but should. /MPlayer|VLC/ floating=on + # ROX puts all of its windows in the same group, so they open # with the same tags. Disable grouping for ROX Filer. /^ROX-Filer:/ group=0