mirror of https://github.com/0intro/wmii
/foo/ -> ~+!+max rules now working fine, also renamed /client/X/class into /client/X/props, props syntax is now class:instance:name
This commit is contained in:
parent
8a89f37797
commit
cdc57ca2fd
|
@ -12,7 +12,6 @@
|
|||
(stacked) client is made visible. So, when the fifth client is focused
|
||||
and made visible, the third would disappear (with n=2) -- this means on
|
||||
boundaries, like in mutt(1).
|
||||
- make /foo/ -> bar+! -alike rules working
|
||||
- /def/ncol defines num of columns which should be created by default if possible.
|
||||
maybe /tag/ -> 60+20+20 ? or only /tag/ -> tag?
|
||||
- remove internal labels, now tagging seems easy and straightforward that they
|
||||
|
|
|
@ -21,6 +21,7 @@ static void
|
|||
update_client_name(Client *c)
|
||||
{
|
||||
XTextProperty name;
|
||||
XClassHint ch;
|
||||
int n;
|
||||
char **list = nil;
|
||||
|
||||
|
@ -42,6 +43,16 @@ update_client_name(Client *c)
|
|||
}
|
||||
}
|
||||
XFree(name.value);
|
||||
if(XGetClassHint(dpy, c->win, &ch)) {
|
||||
snprintf(c->props, sizeof(c->props), "%s:%s:%s",
|
||||
ch.res_class ? ch.res_class : "",
|
||||
ch.res_name ? ch.res_name : "",
|
||||
c->name);
|
||||
if(ch.res_class)
|
||||
XFree(ch.res_class);
|
||||
if(ch.res_name)
|
||||
XFree(ch.res_name);
|
||||
}
|
||||
}
|
||||
|
||||
Client *
|
||||
|
@ -49,7 +60,6 @@ create_client(Window w, XWindowAttributes *wa)
|
|||
{
|
||||
Client *c = (Client *) cext_emallocz(sizeof(Client));
|
||||
XSetWindowAttributes fwa;
|
||||
XClassHint ch;
|
||||
long msize;
|
||||
static unsigned int id = 1;
|
||||
static char buf[256];
|
||||
|
@ -74,15 +84,6 @@ create_client(Window w, XWindowAttributes *wa)
|
|||
c->fixedsize = False;
|
||||
XAddToSaveSet(dpy, c->win);
|
||||
update_client_name(c);
|
||||
if(XGetClassHint(dpy, c->win, &ch)) {
|
||||
snprintf(c->classinst, sizeof(c->classinst), "%s:%s",
|
||||
ch.res_class ? ch.res_class : "",
|
||||
ch.res_name ? ch.res_name : "");
|
||||
if(ch.res_class)
|
||||
XFree(ch.res_class);
|
||||
if(ch.res_name)
|
||||
XFree(ch.res_name);
|
||||
}
|
||||
fwa.override_redirect = 1;
|
||||
fwa.background_pixmap = ParentRelative;
|
||||
fwa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
|
||||
|
|
36
cmd/wm/fs.c
36
cmd/wm/fs.c
|
@ -62,7 +62,7 @@ enum { WMII_IOUNIT = 2048 };
|
|||
* /tag/X/1/ctl FsFctl command interface (area)
|
||||
* /tag/X/1/mode FsFmode column mode
|
||||
* /tag/X/1/sel/ FsDclient
|
||||
* /tag/X/1/1/class FsFclass Class:instance of client
|
||||
* /tag/X/1/1/props FsFprops Class:instance of client
|
||||
* /tag/X/1/1/index FsFindex index of client in /client
|
||||
* /tag/X/1/1/name FsFname name of client
|
||||
* /tag/X/1/1/tags FsFtags tag of client
|
||||
|
@ -226,7 +226,7 @@ name_of_qid(Qid wqid[IXP_MAX_WELEM], unsigned short qsel)
|
|||
return nil;
|
||||
return "tags";
|
||||
break;
|
||||
case FsFclass:
|
||||
case FsFprops:
|
||||
case FsFindex:
|
||||
case FsFname:
|
||||
if((dir_type == FsDclient) && (i1 == -1 || i2 == -1 || i3 == -1))
|
||||
|
@ -237,8 +237,8 @@ name_of_qid(Qid wqid[IXP_MAX_WELEM], unsigned short qsel)
|
|||
case FsFname:
|
||||
return "name";
|
||||
break;
|
||||
case FsFclass:
|
||||
return "class";
|
||||
case FsFprops:
|
||||
return "props";
|
||||
break;
|
||||
case FsFindex:
|
||||
return "index";
|
||||
|
@ -288,8 +288,8 @@ type_of_name(Qid wqid[IXP_MAX_WELEM], unsigned short qsel, char *name)
|
|||
return FsFctl;
|
||||
if(!strncmp(name, "event", 6))
|
||||
return FsFevent;
|
||||
if(!strncmp(name, "class", 6))
|
||||
return FsFclass;
|
||||
if(!strncmp(name, "props", 6))
|
||||
return FsFprops;
|
||||
if(!strncmp(name, "index", 6))
|
||||
return FsFindex;
|
||||
if(!strncmp(name, "name", 5))
|
||||
|
@ -448,7 +448,7 @@ qid_of_name(Qid wqid[IXP_MAX_WELEM], unsigned short qsel, char *name)
|
|||
if(dir_type == FsDview)
|
||||
return nil;
|
||||
case FsFname:
|
||||
case FsFclass:
|
||||
case FsFprops:
|
||||
if(dir_type == FsDroot)
|
||||
return nil;
|
||||
case FsFtags:
|
||||
|
@ -550,13 +550,13 @@ stat_of_name(Stat *stat, char *name, Qid wqid[IXP_MAX_WELEM], unsigned short qse
|
|||
snprintf(buf, sizeof(buf), "%d %d %d %d", fr.x, fr.y, fr.width, fr.height);
|
||||
return pack_stat(stat, wqid, qsel, name, strlen(buf), IXP_DMREAD | IXP_DMWRITE);
|
||||
break;
|
||||
case FsFclass:
|
||||
case FsFprops:
|
||||
if(dir_type == FsDclient) {
|
||||
f = view.data[i1]->area.data[i2]->frame.data[i3];
|
||||
return pack_stat(stat, wqid, qsel, name, strlen(f->client->classinst), IXP_DMREAD);
|
||||
return pack_stat(stat, wqid, qsel, name, strlen(f->client->props), IXP_DMREAD);
|
||||
}
|
||||
else
|
||||
return pack_stat(stat, wqid, qsel, name, strlen(client.data[i1]->classinst), IXP_DMREAD);
|
||||
return pack_stat(stat, wqid, qsel, name, strlen(client.data[i1]->props), IXP_DMREAD);
|
||||
break;
|
||||
case FsFindex:
|
||||
switch(dir_type) {
|
||||
|
@ -1093,7 +1093,7 @@ xread(IXPConn *c, Fcall *fcall)
|
|||
break;
|
||||
case FsDGclient:
|
||||
case FsDclient:
|
||||
fcall->count = stat_of_name(&stat, "class", m->wqid, m->sel);
|
||||
fcall->count = stat_of_name(&stat, "props", m->wqid, m->sel);
|
||||
p = ixp_pack_stat(p, &stat);
|
||||
fcall->count += stat_of_name(&stat, "name", m->wqid, m->sel);
|
||||
p = ixp_pack_stat(p, &stat);
|
||||
|
@ -1130,14 +1130,14 @@ xread(IXPConn *c, Fcall *fcall)
|
|||
fcall->count = strlen(buf);
|
||||
memcpy(p, buf, fcall->count);
|
||||
break;
|
||||
case FsFclass:
|
||||
case FsFprops:
|
||||
if(dir_type == FsDclient) {
|
||||
if((fcall->count = strlen(view.data[i1]->area.data[i2]->frame.data[i3]->client->classinst)))
|
||||
memcpy(p, view.data[i1]->area.data[i2]->frame.data[i3]->client->classinst, fcall->count);
|
||||
if((fcall->count = strlen(view.data[i1]->area.data[i2]->frame.data[i3]->client->props)))
|
||||
memcpy(p, view.data[i1]->area.data[i2]->frame.data[i3]->client->props, fcall->count);
|
||||
}
|
||||
else {
|
||||
if((fcall->count = strlen(client.data[i1]->classinst)))
|
||||
memcpy(p, client.data[i1]->classinst, fcall->count);
|
||||
if((fcall->count = strlen(client.data[i1]->props)))
|
||||
memcpy(p, client.data[i1]->props, fcall->count);
|
||||
}
|
||||
break;
|
||||
case FsFindex:
|
||||
|
@ -1371,13 +1371,11 @@ xwrite(IXPConn *c, Fcall *fcall)
|
|||
memcpy(buf, fcall->data, fcall->count);
|
||||
buf[fcall->count] = 0;
|
||||
cext_trim(buf, " \t/");
|
||||
if(!permit_tags(buf))
|
||||
return Ebadvalue;
|
||||
if(dir_type == FsDclient)
|
||||
cl = view.data[i1]->area.data[i2]->frame.data[i3]->client;
|
||||
else
|
||||
cl = client.data[i1];
|
||||
cext_strlcpy(cl->tags, buf, sizeof(cl->tags));
|
||||
apply_tags(cl, buf);
|
||||
update_views();
|
||||
draw_client(cl);
|
||||
break;
|
||||
|
|
140
cmd/wm/rule.c
140
cmd/wm/rule.c
|
@ -9,14 +9,8 @@
|
|||
#include <regex.h>
|
||||
#include "wm.h"
|
||||
|
||||
/*
|
||||
* basic rule matching language
|
||||
*
|
||||
* /regex/ -> tag [tag ...]
|
||||
*
|
||||
* regex might contain POSIX regex syntax defined in regex(3)
|
||||
*/
|
||||
|
||||
/* basic rule matching language /regex/ -> value
|
||||
* regex might contain POSIX regex syntax defined in regex(3) */
|
||||
enum {
|
||||
IGNORE,
|
||||
REGEX,
|
||||
|
@ -25,13 +19,10 @@ enum {
|
|||
|
||||
typedef struct {
|
||||
regex_t regex;
|
||||
char tags[256];
|
||||
Bool is_valid;
|
||||
char values[256];
|
||||
} Rule;
|
||||
VECTOR(RuleVector, Rule *);
|
||||
|
||||
VECTOR(PropVector, char *);
|
||||
|
||||
static RuleVector rule;
|
||||
|
||||
static Vector *
|
||||
|
@ -40,29 +31,14 @@ vector_of_rules(RuleVector *rv)
|
|||
return (Vector *) rv;
|
||||
}
|
||||
|
||||
static Vector *
|
||||
vector_of_props(PropVector *pv)
|
||||
{
|
||||
return (Vector *) pv;
|
||||
}
|
||||
|
||||
Bool
|
||||
permit_tags(const char *tags)
|
||||
static Bool
|
||||
permit_tag(const char *tag)
|
||||
{
|
||||
static char *exclude[] = { "sel", "status" };
|
||||
char buf[256];
|
||||
char *toks[16];
|
||||
unsigned int i, j, n;
|
||||
|
||||
cext_strlcpy(buf, tags, sizeof(buf));
|
||||
if(!(n = cext_tokenize(toks, 16, buf, '+')))
|
||||
return False;
|
||||
for(i = 0; i < (sizeof(exclude)/sizeof(exclude[0])); i++)
|
||||
for(j = 0; j < n; j++) {
|
||||
if(!strncmp(exclude[i], toks[j], strlen(toks[j])) &&
|
||||
!strncmp(exclude[i], toks[j], strlen(exclude[i])))
|
||||
return False;
|
||||
}
|
||||
unsigned int i;
|
||||
for(i = 0; i < (sizeof(exclude) / sizeof(exclude[0])); i++)
|
||||
if(!strcmp(exclude[i], tag))
|
||||
return False;
|
||||
return True;
|
||||
}
|
||||
|
||||
|
@ -71,15 +47,14 @@ update_rules()
|
|||
{
|
||||
unsigned int i;
|
||||
int mode = IGNORE;
|
||||
char *p, *r = nil, *t = nil, regex[256], tags[256];
|
||||
char *p, *r = nil, *v = nil, regex[256], values[256];
|
||||
|
||||
if(!def.rules || !strlen(def.rules))
|
||||
return;
|
||||
|
||||
while(rule.size) {
|
||||
Rule *r = rule.data[0];
|
||||
if(r->is_valid)
|
||||
regfree(&r->regex);
|
||||
regfree(&r->regex);
|
||||
cext_vdetach(vector_of_rules(&rule), r);
|
||||
free(r);
|
||||
}
|
||||
|
@ -93,8 +68,8 @@ update_rules()
|
|||
}
|
||||
else if(*p == '>') {
|
||||
mode = TAGS;
|
||||
tags[0] = 0;
|
||||
t = tags;
|
||||
values[0] = 0;
|
||||
v = values;
|
||||
}
|
||||
break;
|
||||
case REGEX:
|
||||
|
@ -109,22 +84,20 @@ update_rules()
|
|||
break;
|
||||
case TAGS:
|
||||
if(*p == '\n' || *(p + 1) == 0) {
|
||||
*t = 0;
|
||||
cext_trim(tags, " \t/");
|
||||
if(permit_tags(tags)) {
|
||||
Rule *rul = cext_emallocz(sizeof(Rule));
|
||||
rul->is_valid = !regcomp(&rul->regex, regex, 0);
|
||||
cext_strlcpy(rul->tags, tags, sizeof(rul->tags));
|
||||
Rule *rul = cext_emallocz(sizeof(Rule));
|
||||
*v = 0;
|
||||
cext_trim(values, " \t/");
|
||||
if(!regcomp(&rul->regex, regex, 0)) {
|
||||
cext_strlcpy(rul->values, values, sizeof(rul->values));
|
||||
cext_vattach(vector_of_rules(&rule), rul);
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "wmiiwm: ignoring rule with tags '%s', restricted tag name\n",
|
||||
tags);
|
||||
free(rul);
|
||||
mode = IGNORE;
|
||||
}
|
||||
else {
|
||||
*t = *p;
|
||||
t++;
|
||||
*v = *p;
|
||||
v++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -133,49 +106,64 @@ update_rules()
|
|||
update_views();
|
||||
}
|
||||
|
||||
static void
|
||||
match(Client *c, PropVector prop)
|
||||
void
|
||||
apply_tags(Client *c, const char *tags)
|
||||
{
|
||||
unsigned int i,j;
|
||||
unsigned int i, j = 0, n;
|
||||
char buf[256];
|
||||
char *toks[16], *apply[16];
|
||||
|
||||
cext_strlcpy(buf, tags, sizeof(buf));
|
||||
if(!(n = cext_tokenize(toks, 16, buf, '+')))
|
||||
return;
|
||||
|
||||
for(i = 0; i < n; i++) {
|
||||
if(!strncmp(toks[i], "~", 2))
|
||||
c->floating = True;
|
||||
else if(!strncmp(toks[i], "!", 2)) {
|
||||
if(view.size)
|
||||
apply[j++] = view.data[sel]->name;
|
||||
else
|
||||
apply[j++] = "nil";
|
||||
}
|
||||
else if(permit_tag(toks[i]))
|
||||
apply[j++] = toks[i];
|
||||
}
|
||||
|
||||
c->tags[0] = 0;
|
||||
for(i = 0; i < j; i++) {
|
||||
cext_strlcat(c->tags, apply[i], sizeof(c->tags) - strlen(c->tags) - 1);
|
||||
if(i + 1 < j)
|
||||
cext_strlcat(c->tags, "+", sizeof(c->tags) - strlen(c->tags) - 1);
|
||||
}
|
||||
|
||||
if(!strlen(c->tags))
|
||||
apply_tags(c, "nil");
|
||||
}
|
||||
|
||||
static void
|
||||
match(Client *c, const char *prop)
|
||||
{
|
||||
unsigned int i;
|
||||
regmatch_t tmpregm;
|
||||
|
||||
for(i = 0; i < rule.size; i++) {
|
||||
Rule *r = rule.data[i];
|
||||
for(j=0; j < prop.size; j++)
|
||||
if(r->is_valid && !regexec(&r->regex, prop.data[j], 1, &tmpregm, 0)) {
|
||||
if(!strncmp(r->tags, "~", 2))
|
||||
c->floating = True;
|
||||
else if(!strlen(c->tags) || !strncmp(c->tags, "nil", 4)) {
|
||||
if(!strncmp(r->tags, "!", 2)) {
|
||||
if(view.size)
|
||||
cext_strlcpy(c->tags, view.data[sel]->name, sizeof(c->tags));
|
||||
else
|
||||
cext_strlcpy(c->tags, "nil", sizeof(c->tags));
|
||||
}
|
||||
else
|
||||
cext_strlcpy(c->tags, r->tags, sizeof(c->tags));
|
||||
}
|
||||
}
|
||||
if(!regexec(&r->regex, prop, 1, &tmpregm, 0))
|
||||
if(!strlen(c->tags) || !strncmp(c->tags, "nil", 4))
|
||||
apply_tags(c, r->values);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
apply_rules(Client *c)
|
||||
{
|
||||
PropVector prop = {0};
|
||||
|
||||
if(!def.rules)
|
||||
goto Fallback;
|
||||
|
||||
cext_vattach(vector_of_props(&prop), c->classinst);
|
||||
cext_vattach(vector_of_props(&prop), c->name);
|
||||
|
||||
match(c, prop);
|
||||
|
||||
while(prop.size)
|
||||
cext_vdetach(vector_of_props(&prop), prop.data[0]);
|
||||
match(c, c->props);
|
||||
|
||||
Fallback:
|
||||
if(!strlen(c->tags))
|
||||
cext_strlcpy(c->tags, "nil", sizeof(c->tags));
|
||||
apply_tags(c, "nil");
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ enum {
|
|||
FsFctl,
|
||||
FsFname,
|
||||
FsFrules,
|
||||
FsFclass,
|
||||
FsFprops,
|
||||
FsFmode,
|
||||
FsFtags,
|
||||
FsFindex,
|
||||
|
@ -114,7 +114,7 @@ struct Client {
|
|||
char name[256];
|
||||
char tags[256];
|
||||
ViewVector view;
|
||||
char classinst[256];
|
||||
char props[512];
|
||||
int proto;
|
||||
unsigned int border;
|
||||
Bool floating;
|
||||
|
@ -293,7 +293,7 @@ void snap_move(XRectangle *r, XRectangle *rects, unsigned int num,
|
|||
/* rule.c */
|
||||
void update_rules();
|
||||
void apply_rules(Client *c);
|
||||
Bool permit_tags(const char *tags);
|
||||
void apply_tags(Client *c, const char *tags);
|
||||
|
||||
/* view.c */
|
||||
void arrange_view(View *v);
|
||||
|
|
Loading…
Reference in New Issue