Add group and default-tags keys to /rules.

Update issue #178
Status: Fixed
If you don't want grouping behavior for a client, set group=0 for
that client in /rules. This will inhibit the affinity for tags and
for columns.
This commit is contained in:
Kris Maglione 2010-06-01 22:38:33 -04:00
parent 9055d8e8a1
commit 7da961ec6c
9 changed files with 180 additions and 69 deletions

View File

@ -320,6 +320,7 @@ message_event(Window *w, void *aux, XClientMessageEvent *e) {
if(e->format != 32) if(e->format != 32)
return false; return false;
dnd = (Dnd){0}; dnd = (Dnd){0};
dnd.dest = ~0UL;
dnd.source = l[0]; dnd.source = l[0];
bcopy(&l[1], dnd.data, sizeof dnd.data); bcopy(&l[1], dnd.data, sizeof dnd.data);
@ -372,7 +373,6 @@ message_event(Window *w, void *aux, XClientMessageEvent *e) {
Long(r.min), (Dx(r)<<16) | Dy(r), l[4]); Long(r.min), (Dx(r)<<16) | Dy(r), l[4]);
break; break;
} }
return false; return false;
}else }else
if(msg == xatom("XdndDrop") || msg == xatom("XdndFinished")) { if(msg == xatom("XdndDrop") || msg == xatom("XdndFinished")) {

View File

@ -23,7 +23,7 @@ enum {
static Group* group; static Group* group;
static void void
group_init(Client *c) { group_init(Client *c) {
Group *g; Group *g;
long *ret; long *ret;
@ -53,12 +53,13 @@ group_init(Client *c) {
g->ref++; g->ref++;
} }
static void void
group_remove(Client *c) { group_remove(Client *c) {
Group **gp; Group **gp;
Group *g; Group *g;
g = c->group; g = c->group;
c->group = nil;
if(g == nil) if(g == nil)
return; return;
if(g->client == c) if(g->client == c)
@ -200,11 +201,18 @@ apply_rules(Client *c) {
IxpMsg m; IxpMsg m;
Rule *r; Rule *r;
Ruleval *rv; Ruleval *rv;
bool ret;
ret = false;
if(def.rules.string) if(def.rules.string)
for(r=def.rules.rule; r; r=r->next) for(r=def.rules.rule; r; r=r->next)
if(regexec(r->regex, c->props, nil, 0)) { if(regexec(r->regex, c->props, nil, 0)) {
for(rv=r->values; rv; rv=rv->next) { for(rv=r->values; rv; rv=rv->next) {
if(!strcmp(rv->key, "default-tags")) {
utflcpy(c->tags, rv->value, sizeof c->tags);
ret = true;
}
else {
bufclear(); bufclear();
bufprint("%s %s", rv->key, rv->value); bufprint("%s %s", rv->key, rv->value);
m = ixp_message(buffer, sizeof buffer, MsgPack); m = ixp_message(buffer, sizeof buffer, MsgPack);
@ -213,6 +221,7 @@ apply_rules(Client *c) {
poperror(); poperror();
} }
} }
}
return true; return true;
} }
@ -228,25 +237,27 @@ client_manage(Client *c) {
Client *leader; Client *leader;
Frame *f; Frame *f;
char *tags; char *tags;
bool rules; bool dotags;
if(Dx(c->r) == Dx(screen->r)) if(Dx(c->r) == Dx(screen->r))
if(Dy(c->r) == Dy(screen->r)) if(Dy(c->r) == Dy(screen->r))
if(c->w.ewmh.type == 0) if(c->w.ewmh.type == 0)
fullscreen(c, true, -1); fullscreen(c, true, -1);
tags = getprop_string(&c->w, "_WMII_TAGS"); dotags = apply_rules(c);
rules = apply_rules(c);
if(!c->tags[0] || dotags) {
leader = win2client(c->trans); leader = win2client(c->trans);
if(leader == nil && c->group) if(leader == nil && c->group)
leader = group_leader(c->group); leader = group_leader(c->group);
if(tags) // && (!leader || leader == c || starting)) tags = getprop_string(&c->w, "_WMII_TAGS");
if(tags)
utflcpy(c->tags, tags, sizeof c->tags); utflcpy(c->tags, tags, sizeof c->tags);
else if(leader && !rules) else if(leader)
utflcpy(c->tags, leader->tags, sizeof c->tags); utflcpy(c->tags, leader->tags, sizeof c->tags);
free(tags); free(tags);
}
if(c->tags[0]) if(c->tags[0])
client_applytags(c, c->tags); client_applytags(c, c->tags);
@ -1064,10 +1075,10 @@ static char *badtags[] = {
char* char*
client_extratags(Client *c) { client_extratags(Client *c) {
Fmt fmt;
Frame *f; Frame *f;
char *toks[32]; char *toks[32];
char **tags; char **tags;
char *s, *s2;
int i; int i;
i = 0; i = 0;
@ -1078,28 +1089,21 @@ client_extratags(Client *c) {
toks[i] = nil; toks[i] = nil;
tags = comm(CLeft, toks, c->retags); tags = comm(CLeft, toks, c->retags);
s = nil; fmtstrinit(&fmt);
if(i > 1) if(i > 1)
s = join(tags, "+"); join(tags, "+", &fmt);
free(tags); free(tags);
if(!c->tagre.regex && !c->tagvre.regex)
return s;
if(c->tagre.regex) { if(c->tagre.regex)
s2 = s; fmtprint(&fmt, "+/%s/", c->tagre.regex);
s = smprint("%s+/%s/", s ? s : "", c->tagre.regex); if(c->tagvre.regex)
free(s2); fmtprint(&fmt, "-/%s/", c->tagvre.regex);
} return fmtstrflush(&fmt);
if(c->tagvre.regex) {
s2 = s;
s = smprint("%s-/%s/", s ? s : "", c->tagvre.regex);
free(s2);
}
return s;
} }
bool bool
client_applytags(Client *c, const char *tags) { client_applytags(Client *c, const char *tags) {
Fmt fmt;
uint i, j, k, n; uint i, j, k, n;
bool add, found; bool add, found;
char buf[512], last; char buf[512], last;
@ -1203,12 +1207,15 @@ client_applytags(Client *c, const char *tags) {
qsort(toks, j, sizeof *toks, strpcmp); qsort(toks, j, sizeof *toks, strpcmp);
uniq(toks); uniq(toks);
s = join(toks, "+"); fmtstrinit(&fmt);
utflcpy(c->tags, s, sizeof c->tags); join(toks, "+", &fmt);
if(c->tagre.regex) if(c->tagre.regex)
strlcatprint(c->tags, sizeof c->tags, "+/%s/", c->tagre.regex); fmtprint(&fmt, "+/%s/", c->tagre.regex);
if(c->tagvre.regex) if(c->tagvre.regex)
strlcatprint(c->tags, sizeof c->tags, "-/%s/", c->tagvre.regex); fmtprint(&fmt, "-/%s/", c->tagvre.regex);
s = fmtstrflush(&fmt);
utflcpy(c->tags, s, sizeof c->tags);
changeprop_string(&c->w, "_WMII_TAGS", c->tags); changeprop_string(&c->w, "_WMII_TAGS", c->tags);
free(s); free(s);

View File

@ -92,7 +92,9 @@ void client_unmap(Client*, int state);
Frame* client_viewframe(Client *c, View *v); Frame* client_viewframe(Client *c, View *v);
void focus(Client*, bool user); void focus(Client*, bool user);
void fullscreen(Client*, int, long); void fullscreen(Client*, int, long);
void group_init(Client*);
Client* group_leader(Group*); Client* group_leader(Group*);
void group_remove(Client*);
int map_frame(Client*); int map_frame(Client*);
Client* selclient(void); Client* selclient(void);
int unmap_frame(Client*); int unmap_frame(Client*);

View File

@ -37,6 +37,7 @@ enum {
LFONTPAD, LFONTPAD,
LFULLSCREEN, LFULLSCREEN,
LGRABMOD, LGRABMOD,
LGROUP,
LGROW, LGROW,
LINCMODE, LINCMODE,
LKILL, LKILL,
@ -74,6 +75,7 @@ char *symtab[] = {
"fontpad", "fontpad",
"fullscreen", "fullscreen",
"grabmod", "grabmod",
"group",
"grow", "grow",
"incmode", "incmode",
"kill", "kill",
@ -387,6 +389,7 @@ readctl_client(Client *c) {
bufprint("fullscreen %d\n", c->fullscreen); bufprint("fullscreen %d\n", c->fullscreen);
else else
bufprint("fullscreen off\n"); bufprint("fullscreen off\n");
bufprint("group 0x%ulx\n", c->group ? c->group->leader : 0);
bufprint("tags %s\n", c->tags); bufprint("tags %s\n", c->tags);
bufprint("urgent %s\n", TOGGLE(c->urgent)); bufprint("urgent %s\n", TOGGLE(c->urgent));
return buffer; return buffer;
@ -423,6 +426,12 @@ message_client(Client *c, IxpMsg *m) {
else else
fullscreen(c, gettoggle(s), -1); fullscreen(c, gettoggle(s), -1);
break; break;
case LGROUP:
group_remove(c);
c->w.hints->group = msg_getulong(msg_getword(m));
if(c->w.hints->group)
group_init(c);
break;
case LKILL: case LKILL:
client_kill(c, true); client_kill(c, true);
break; break;

View File

@ -3,9 +3,8 @@
*/ */
#include <stuff/geom.h> #include <stuff/geom.h>
#include <stdarg.h> #include <stdarg.h>
#include <fmt.h>
#include <regexp9.h> #include <regexp9.h>
/* Types */ /* Types */
@ -53,7 +52,7 @@ bool getint(const char*, int*);
bool getlong(const char*, long*); bool getlong(const char*, long*);
bool getulong(const char*, ulong*); bool getulong(const char*, ulong*);
void grep(char**, Reprog*, int); void grep(char**, Reprog*, int);
char* join(char**, char*); char* join(char**, char*, Fmt*);
int max(int, int); int max(int, int);
int min(int, int); int min(int, int);
char* pathsearch(const char*, const char*, bool); char* pathsearch(const char*, const char*, bool);

View File

@ -5,18 +5,23 @@
#include "util.h" #include "util.h"
char* char*
join(char **list, char *sep) { join(char **list, char *sep, Fmt *f) {
Fmt f; Fmt fmt;
char **p; char **p;
if(fmtstrinit(&f) < 0) if(f == nil) {
f = &fmt;
if(fmtstrinit(f) < 0)
abort(); abort();
}
for(p=list; *p; p++) { for(p=list; *p; p++) {
if(p != list) if(p != list)
fmtstrcpy(&f, sep); fmtstrcpy(f, sep);
fmtstrcpy(&f, *p); fmtstrcpy(f, *p);
} }
return fmtstrflush(&f); if(f != &fmt)
return nil;
return fmtstrflush(f);
} }

View File

@ -5,8 +5,10 @@
% have to be post-processed. The _italic_ hack is necessary for % have to be post-processed. The _italic_ hack is necessary for
% italicising things like /_foo_/, which txt2tags will ignore. % italicising things like /_foo_/, which txt2tags will ignore.
% The others need to work in ``` lines. % The others need to work in ``` lines.
%!preproc(man): \bPROVISIONAL\b **PROVISIONAL**
%!postproc(man): (<.*?>) \\fI\1\\fR %!postproc(man): (<.*?>) \\fI\1\\fR
%!postproc(man): \b_(.*?)_ \\fI\1\\fR %!postproc(man): \b_(.*?)_ \\fI\1\\fR
%!postproc(man): \\e_ _
%!postproc(man): `(.*?)` \\fB\1\\fR %!postproc(man): `(.*?)` \\fB\1\\fR
%!postproc(man): (\[.*?\]) \\fI\1\\fR %!postproc(man): (\[.*?\]) \\fI\1\\fR
%!postproc(man): \+$ \n.P %!postproc(man): \+$ \n.P

View File

@ -1,4 +1,4 @@
.TH "WMII" 1 "Oct, 2009" "wmii-@VERSION@" .TH "WMII" 1 "2010 June" "wmii-@VERSION@"
.SH NAME .SH NAME
.P .P
@ -284,12 +284,43 @@ matches \fI<regex>\fR, it is given the \fI<n>\fRth supplied \fI<width>\fR.
If there is no \fI<n>\fRth width, it is given 1/\fI<ncol>\fRth of the If there is no \fI<n>\fRth width, it is given 1/\fI<ncol>\fRth of the
screen. screen.
.TP
rules
\fBPROVISIONAL\fR
The \fIrules\fR file contains a list of rules that may be used
to automatically set properties of new clients. Rules are
specified as:
.nf
/\fI<regex>\fR/ \fI<key>\fR=\fI<value>\fR ...
.fi
where each \fI<key>\fR represents a command in the clients \fIctl\fR
file, and each \fI<value>\fR represents the value to assign to it.
The rules are applied when the client is first started and
the contents of the \fIprops\fR file match the regular
expression \fI<regex>\fR.
Additionally, the following keys are accepted and have
special meaning:
.RS 8
.TP
default\-tags \fI<tags>\fR
Like \fItags\fR, but only sets the tags if they can't be
obtained from the client's group or from the
_WMII_TAGS window property. This key should be
preferred to the \fItags\fR key in most cases.
.RS -8
.TP .TP
tagrules tagrules
The \fItagrules\fR file contains a list of The \fItagrules\fR file contains a list of
rules similar to the colrules. These rules specify rules similar to the colrules. These rules specify
the tags a client is to be given when it is created. the tags a client is to be given when it is created.
Rules are specified: Rules are specified as:
.nf .nf
/\fI<regex>\fR/ -> \fI<tag>\fR\fI[+\fI<tag>\fR]\fR* /\fI<regex>\fR/ -> \fI<tag>\fR\fI[+\fI<tag>\fR]\fR*
@ -374,16 +405,33 @@ of the client. The following commands may be written to
it: it:
.RS 8 .RS 8
.TP .TP
floating \fI<on | off | toggle>\fR
Defines whether this client is likely to float when
attached to a new view.
.TP
fullscreen \fI<on | off | toggle>\fR
Sets the client's fullscreen state.
.TP
group \fI<group id>\fR
The client's group ID, or 0 if not part of a group.
Clients tend to open with the same tags and in the
same columns as the last active member of their
group. Setting this property is only useful when
done via the rules file.
.TP
kill kill
Close the client's window. This command will Close the client's window.
likely kill the X client in the future
(including its other windows), while the close
command will replace it.
.TP .TP
Urgent \fI<on | off | toggle>\fR slay
Forcibly kill the client's connection to the X
server, closing all of its windows. Kill the parent
process if the client provides its PID.
.TP
tags \fI<tags>\fR
The client's tags. The same as the tags file.
.TP
urgent \fI<on | off | toggle>\fR
Set or unset the client's urgent hint. Set or unset the client's urgent hint.
.TP
Fullscreen \fI<on | off | toggle>\fR
.RS -8 .RS -8
.TP .TP
@ -392,7 +440,7 @@ Set or read a client's label (title).
.TP .TP
props props
Returns a clients class and label as: Returns a clients class and label as:
\fI<name>\fR:\fI<class>\fR:\fI<label>\fR \fI<instance>\fR:\fI<class>\fR:\fI<label>\fR.
.TP .TP
tags tags
Set or read a client's tags. Tags are separated by Set or read a client's tags. Tags are separated by

View File

@ -1,6 +1,6 @@
WMII WMII
wmii-@VERSION@ wmii-@VERSION@
Oct, 2009 2010 June
%!includeconf: header.t2t %!includeconf: header.t2t
@ -252,11 +252,37 @@ follows.
If there is no <n>th width, it is given 1/<ncol>th of the If there is no <n>th width, it is given 1/<ncol>th of the
screen. screen.
: rules
PROVISIONAL
The _rules_ file contains a list of rules that may be used
to automatically set properties of new clients. Rules are
specified as:
``` /<regex>/ <key>=<value> ...
where each <key> represents a command in the clients _ctl_
file, and each <value> represents the value to assign to it.
The rules are applied when the client is first started and
the contents of the _props_ file match the regular
expression <regex>.
Additionally, the following keys are accepted and have
special meaning:
>>
: default-tags <tags>
Like _tags_, but only sets the tags if they can't be
obtained from the client's group or from the
\_WMII_TAGS window property. This key should be
preferred to the _tags_ key in most cases.
<<
: tagrules : tagrules
The _tagrules_ file contains a list of The _tagrules_ file contains a list of
rules similar to the colrules. These rules specify rules similar to the colrules. These rules specify
the tags a client is to be given when it is created. the tags a client is to be given when it is created.
Rules are specified: Rules are specified as:
``` /<regex>/ -> <tag>[+<tag>]* ``` /<regex>/ -> <tag>[+<tag>]*
@ -326,21 +352,34 @@ represents the currently selected client.
of the client. The following commands may be written to of the client. The following commands may be written to
it: it:
>> >>
: floating <on | off | toggle>
Defines whether this client is likely to float when
attached to a new view.
: fullscreen <on | off | toggle>
Sets the client's fullscreen state.
: group <group id>
The client's group ID, or 0 if not part of a group.
Clients tend to open with the same tags and in the
same columns as the last active member of their
group. Setting this property is only useful when
done via the rules file.
: kill : kill
Close the client's window. This command will Close the client's window.
likely kill the X client in the future : slay
(including its other windows), while the close Forcibly kill the client's connection to the X
command will replace it. server, closing all of its windows. Kill the parent
: Urgent <on | off | toggle> process if the client provides its PID.
: tags <tags>
The client's tags. The same as the tags file.
: urgent <on | off | toggle>
Set or unset the client's urgent hint. Set or unset the client's urgent hint.
: Fullscreen <on | off | toggle>
<< <<
: label : label
Set or read a client's label (title). Set or read a client's label (title).
: props : props
Returns a clients class and label as: Returns a clients class and label as:
<name>:<class>:<label> <instance>:<class>:<label>.
: tags : tags
Set or read a client's tags. Tags are separated by Set or read a client's tags. Tags are separated by
**+** or **-**. Tags beginning with **+** are **+** or **-**. Tags beginning with **+** are