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