wmii

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

commit 68b77ab4e8e55214a4e71626e94e0a126fe23d41
parent ec18eb22e960272a122c8427540fc123af110619
Author: Kris Maglione <kris@suckless.org>
Date:   Fri, 25 Jun 2010 17:21:12 -0400

Change format of bar files. Refactor fs.c. Add M-n/M-b to rc scripts. Add showkeys to plan9port rc. Update docs. Linkify code fragments in wmii.tex.

Diffstat:
alternative_wmiircs/plan9port/wmiirc | 142+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
alternative_wmiircs/python/pygmi/fs.py | 143+++++++++++++++++++++++++++++++++++++------------------------------------------
cmd/wmii.rc.rc | 15+++++++++++----
cmd/wmii.sh.sh | 12++++++++----
cmd/wmii/bar.c | 28----------------------------
cmd/wmii/dat.h | 3++-
cmd/wmii/fns.h | 3++-
cmd/wmii/fs.c | 193++++++++++++++++++++++++++++++++++++-------------------------------------------
cmd/wmii/message.c | 29+++++++++++++++++++++++++++++
doc/wmii.tex | 307++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
include/stuff/base.h | 4+++-
man/wmii.man1 | 11+++++------
rc/wmiirc.sh | 43+++++++++++++++++++++----------------------
13 files changed, 511 insertions(+), 422 deletions(-)

diff --git a/alternative_wmiircs/plan9port/wmiirc b/alternative_wmiircs/plan9port/wmiirc @@ -61,8 +61,8 @@ wmiir write /rules <<! # Status Bar Info fn status { - echo -n `{uptime | sed 's/.*://; s/,//g'} '|' \ - `{date} } + echo -n label `{uptime | sed 's/.*://; s/,//g'} '|' \ + `{date} } # Generic overridable startup details fn startup { witray & } @@ -86,19 +86,19 @@ fn sigexit { wi_cleankeys} fn Event-CreateTag { - echo $wmiinormcol $* | wmiir create /lbar/$"*} + echo colors $wmiinormcol $wi_newline label $* | wmiir create /lbar/$"*} fn Event-DestroyTag { wmiir remove /lbar/$"*} fn Event-FocusTag { - wmiir xwrite /lbar/$"* $wmiifocuscol $*} + wmiir xwrite /lbar/$"* colors $wmiifocuscol} fn Event-UnfocusTag { - wmiir xwrite /lbar/$"* $wmiinormcol $*} + wmiir xwrite /lbar/$"* colors $wmiinormcol} fn Event-UrgentTag { shift - wmiir xwrite /lbar/$"* '*'$"*} + wmiir xwrite /lbar/$"* label '*'$"*} fn Event-NotUrgentTag { shift - wmiir xwrite /lbar/$"* $"*} + wmiir xwrite /lbar/$"* label $"*} fn Event-AreaFocus { if(~ $1 '~') setbackground $wmiifloatbackground @@ -116,7 +116,7 @@ fn Event-Unresponsive { wmiir xwrite /client/$client/ctl slay }&} fn Event-Notice { - wmiir xwrite $noticebar $wi_arg + wmiir xwrite $noticebar label $wi_arg /bin/kill $xpid >[2]/dev/null # Let's hope this isn't reused... { sleep $noticetimeout; wmiir xwrite $noticebar ' ' }& # Bug... @@ -152,21 +152,24 @@ fn Event-LeftBarMouseDown { wi_fnmenu LBar $* &} # Actions +fn Action-exec { + wmiir xwrite /ctl exec $*} +fn Action-quit { + wmiir xwrite /ctl quit} fn Action-rehash { comm -23 <{ls `{namespace}^/proglist.* >[2]/dev/null | awk -F'.' '{print $NF}'} \ <{ps | awk '{print $2}'} | while(id=`{read}) rm `{namespace}^/proglist.$id wi_proglist $PATH >$progs_file} -fn Action-quit { - wmiir xwrite /ctl quit} -fn Action-exec { - wmiir xwrite /ctl exec $*} +fn Action-showkeys { + echo $wmiikeyhelp | xmessage -file - +} fn Action-status { flag x -; flag r - if(wmiir remove /rbar/status >[2]/dev/null) sleep 2 - echo $wmiinormcol | wmiir create /rbar/status + echo colors $wmiinormcol | wmiir create /rbar/status while(status | wmiir write /rbar/status) sleep 1 } @@ -181,84 +184,103 @@ startup # Key Bindings _keys = `{wi_getfuns Key} +fn keygroup { + wmiikeyhelp = $wmiikeyhelp ^ $wi_newline ^ ' ' ^ $"* ^ $wi_newline} fn key { + help=$1; shift key=() - for(k) if(! ~ $k $_keys) key = ($key Key-$k) + for(k) { + if(! ~ $k $_keys) { + ifs=() { wmiikeyhelp = `{awk 'BEGIN { + printf "%s %- 20s %s\n", ENVIRON["wmiikeyhelp"], ENVIRON["k"], ENVIRON["help"] + exit }'} } + key = ($key Key-$k)}} ~ $#key 0} -# This is... ugly. - -key $MODKEY-Control-t || fn $key { - switch(`{wmiir read /keys | wc -l}) { - case 0 1 - wmiir xwrite /keys $keys - wmiir xwrite /ctl grabmod $MODKEY - case * - ifs=() { keys=`{wmiir read /keys} } - wmiir xwrite /keys $MODKEY-Control-t - wmiir xwrite /ctl grabmod Mod3 - }} - -key $MODKEY-$LEFT || fn $key { +keygroup Moving around +key 'Select the client to the left' $MODKEY-$LEFT || fn $key { wmiir xwrite /tag/sel/ctl select left} -key $MODKEY-$RIGHT || fn $key { +key 'Select the client to the right' $MODKEY-$RIGHT || fn $key { wmiir xwrite /tag/sel/ctl select right} -key $MODKEY-$DOWN || fn $key { +key 'Select the client below' $MODKEY-$DOWN || fn $key { wmiir xwrite /tag/sel/ctl select down} -key $MODKEY-$UP || fn $key { +key 'Select the client above' $MODKEY-$UP || fn $key { wmiir xwrite /tag/sel/ctl select up} -key $MODKEY-Control-$DOWN || fn $key { + +key 'Toggle between floating and managed layers' $MODKEY-space || fn $key { + wmiir xwrite /tag/sel/ctl select toggle} + +keygroup Moving through stacks +key 'Select the stack below' $MODKEY-Control-$DOWN || fn $key { wmiir xwrite /tag/sel/ctl select down stack} -key $MODKEY-Control-$UP || fn $key { +key 'Select the stack above' $MODKEY-Control-$UP || fn $key { wmiir xwrite /tag/sel/ctl select up stack} -key $MODKEY-Shift-$LEFT || fn $key { +keygroup Moving clients around +key 'Move selected client to the left' $MODKEY-Shift-$LEFT || fn $key { wmiir xwrite /tag/sel/ctl send sel left} -key $MODKEY-Shift-$RIGHT || fn $key { +key 'Move selected client to the right' $MODKEY-Shift-$RIGHT || fn $key { wmiir xwrite /tag/sel/ctl send sel right} -key $MODKEY-Shift-$DOWN || fn $key { +key 'Move selected client down' $MODKEY-Shift-$DOWN || fn $key { wmiir xwrite /tag/sel/ctl send sel down} -key $MODKEY-Shift-$UP || fn $key { +key 'Move selected client up' $MODKEY-Shift-$UP || fn $key { wmiir xwrite /tag/sel/ctl send sel up} -key $MODKEY-f || fn $key { +key 'Toggle selected client between floating and managed layers' $MODKEY-Shift-space || fn $key { + wmiir xwrite /tag/sel/ctl send sel toggle} + +keygroup Client actions +key 'Toggle selected client''s fullsceen state' $MODKEY-f || fn $key { wmiir xwrite /client/sel/ctl Fullscreen toggle} +key 'Close client' $MODKEY-Shift-c || fn $key { + wmiir xwrite /client/sel/ctl kill} -key $MODKEY-space || fn $key { - wmiir xwrite /tag/sel/ctl select toggle} -key $MODKEY-Shift-space || fn $key { - wmiir xwrite /tag/sel/ctl send sel toggle} -key $MODKEY-d || fn $key { +keygroup Changing column modes +key 'Set column to default mode' $MODKEY-d || fn $key { wmiir xwrite /tag/sel/ctl colmode sel default-max} -key $MODKEY-s || fn $key { +key 'Toggle between floating and managed layers' $MODKEY-s || fn $key { wmiir xwrite /tag/sel/ctl colmode sel stack-max} -key $MODKEY-m || fn $key { +key 'Set column to max mode' $MODKEY-m || fn $key { wmiir xwrite /tag/sel/ctl colmode sel stack+max} -key $MODKEY-Shift-c || fn $key { - wmiir xwrite /client/sel/ctl kill} - -key $MODKEY-a || fn $key { +keygroup Running programs +key 'Open wmii actions menu' $MODKEY-a || fn $key { Action `{wi_actions | wimenu -h $hist.action -n $histlen} &} -key $MODKEY-p || fn $key { +key 'Open program menu' $MODKEY-p || fn $key { ifs=() { cmd = `{wimenu -h $hist.prog -n $histlen <$progs_file} } wi_runcmd $cmd & } -key $MODKEY-Return || fn $key { +key 'Launch a terminal' $MODKEY-Return || fn $key { wi_runcmd $WMII_TERM &} -key $MODKEY-t || fn $key { +keygroup Other +key 'Toggle all other key bindings' $MODKEY-Control-t || fn $key { + switch(`{wmiir read /keys | wc -l}) { + case 0 1 + wmiir xwrite /keys $keys + wmiir xwrite /ctl grabmod $MODKEY + case * + ifs=() { keys=`{wmiir read /keys} } + wmiir xwrite /keys $MODKEY-Control-t + wmiir xwrite /ctl grabmod Mod3 + }} + +keygroup Tag actions +key 'Change to another tag' $MODKEY-t || fn $key { tag=`{wi_tags | wimenu -h $hist.tag -n 50} && wmiir xwrite /ctl view $tag &} -key $MODKEY-Shift-t || fn $key { +key 'Retag the selected client' $MODKEY-Shift-t || fn $key { sel=`{wi_selclient} { tag=`{wi_tags | wimenu -h $hist.tag -n 50} && wmiir xwrite /client/$sel/tags $tag } &} +key 'Move to the next tag' $MODKEY-n || fn $key { + wmiir xwrite /ctl view `{wi_tags | wi_nexttag}} +key 'Move to the previous tag' $MODKEY-b || fn $key { + wmiir xwrite /ctl view `{wi_tags | sort -r | wi_nexttag}} -key $MODKEY-^`{seq 0 9} || fn $key { +key 'Move to the numbered view' $MODKEY-^`{seq 0 9} || fn $key { wmiir xwrite /ctl view `{echo $1 | sed 's/.*-//'}} -key Shift-$MODKEY-^`{seq 0 9} || fn $key { +key 'Retag selected client with the numbered tag' Shift-$MODKEY-^`{seq 0 9} || fn $key { wmiir xwrite /client/sel/tags `{echo $1 | sed 's/.*-//'}} - -#` WM Configuration +# WM Configuration wmiir write /ctl <<! grabmod $MODKEY border 2 @@ -286,10 +308,8 @@ ifs=$wi_newline { seltag=`{wi_seltag} for(tag in `{wi_tags}) {{ if(~ $tag $seltag) - echo $wmiifocuscol $tag + echo colors $wmiifocuscol $wi_newline label $tag if not - echo $wmiinormcol $tag + echo colors $wmiinormcol $wi_newline label $tag } | wmiir create /lbar/$tag}} - wi_eventloop - diff --git a/alternative_wmiircs/python/pygmi/fs.py b/alternative_wmiircs/python/pygmi/fs.py @@ -452,82 +452,6 @@ class Tag(Dir): frame = self.framespec(frame) self['grow'] = '%s %s %s' % (frame, dir, str(amount or '')) -class Button(object): - sides = { - 'left': 'lbar', - 'right': 'rbar', - } - def __init__(self, side, name, colors=None, label=None): - self.side = side - self.name = name - self.base_path = self.sides[side] - self.path = '%s/%s' % (self.base_path, self.name) - self.file = None - self._colors = wmii.cache['normcolors'] - self._label = '' - if colors or label: - self.create(colors, label) - - def create(self, colors=None, label=None): - def fail(resp, exc, tb): - self.file = None - if not self.file: - self.file = client.create(self.path, ORDWR) - if colors or label: - self.file.awrite(self.getval(colors, label), offset=0, fail=fail) - - def remove(self): - if self.file: - self.file.aremove() - self.file = None - - def getval(self, colors=None, label=None): - if label is not None: - self._label = label - if colors is not None: - self._colors = colors - return ' '.join([Color(c).hex for c in self._colors or self.colors] + [unicode(self._label or '')]) - - colors = property( - lambda self: self.file and Colors(self.file.read(offset=0).split(' ')[:3]) or (), - lambda self, val: self.create(colors=val)) - - label = property( - lambda self: self.file and self.file.read(offset=0).split(' ', 3)[3] or '', - lambda self, val: self.create(label=val)) - - @classmethod - def all(cls, side): - return (Button(side, s.name) - for s in client.readdir(cls.sides[side]) - if s.name != 'sel') - -class Colors(utf8): - def __init__(self, foreground=None, background=None, border=None): - vals = foreground, background, border - self.vals = tuple(map(Color, vals)) - - def __iter__(self): - return iter(self.vals) - def __list__(self): - return list(self.vals) - def __tuple__(self): - return self.vals - - @classmethod - def from_string(cls, val): - return cls(*val.split(' ')) - - def __getitem__(self, key): - if isinstance(key, basestring): - key = {'foreground': 0, 'background': 1, 'border': 2}[key] - return self.vals[key] - - def __unicode__(self): - return ' '.join(c.hex for c in self.vals) - def __repr__(self): - return 'Colors(%s, %s, %s)' % tuple(repr(c.rgb) for c in self.vals) - class Color(utf8): def __init__(self, colors): if isinstance(colors, Color): @@ -563,6 +487,73 @@ class Color(utf8): def __repr__(self): return 'Color(%s)' % repr(self.rgb) +class Colors(utf8): + def __init__(self, foreground=None, background=None, border=None): + vals = foreground, background, border + self.vals = tuple(map(Color, vals)) + + def __iter__(self): + return iter(self.vals) + def __list__(self): + return list(self.vals) + def __tuple__(self): + return self.vals + + @classmethod + def from_string(cls, val): + return cls(*val.split(' ')) + + def __getitem__(self, key): + if isinstance(key, basestring): + key = {'foreground': 0, 'background': 1, 'border': 2}[key] + return self.vals[key] + + def __unicode__(self): + return ' '.join(c.hex for c in self.vals) + def __repr__(self): + return 'Colors(%s, %s, %s)' % tuple(repr(c.rgb) for c in self.vals) + +class Button(Ctl): + sides = { + 'left': 'lbar', + 'right': 'rbar', + } + ctl_types = { + 'colors': (Colors.from_string, lambda c: str(Colors(*c))), + } + colors = Dir.ctl_property('colors') + label = Dir.ctl_property('label') + + def __init__(self, side, name, colors=None, label=None): + super(Button, self).__init__() + self.side = side + self.name = name + self.base_path = self.sides[side] + self.ctl_path = '%s/%s' % (self.base_path, self.name) + self.file = None + self.create(colors, label) + + def create(self, colors=None, label=None): + def fail(resp, exc, tb): + self.file = None + if not self.file: + self.file = client.create(self.ctl_path, ORDWR) + if colors: + self.colors = colors + if label: + self.label = label + + def remove(self): + if self.file: + self.file.aremove() + self.file = None + + @classmethod + def all(cls, side): + return (Button(side, s.name) + for s in client.readdir(cls.sides[side]) + if s.name != 'sel') + class Rules(collections.MutableMapping, utf8): _items = () diff --git a/cmd/wmii.rc.rc b/cmd/wmii.rc.rc @@ -9,6 +9,7 @@ wmiiscript=$1 wmiikeys=() +wmiikeyhelp='' wi_newline=' ' @@ -134,15 +135,21 @@ fn wi_selclient { wmiir read /client/sel/ctl | sed 1q } -fn wi_readevent { - wmiir read /event +fn wi_nexttag { + awk -v 'curtag='^`{wi_seltag} ' + NR==1 {first = $0} + $0==curtag { if(getline) print $0; else print first; exit }' } fn wi_eventloop { wi_initkeys - wi_readevent | - while(ifs=$wi_ewlinel{wi_event=`{read}}) { + { + if(~ $1 -i) + cat + if not + wmiir read /event + } | while(ifs=$wi_newline{wi_event=`{read}}) { ifs=$wi_newline{ wi_arg=`{echo $wi_event | sed 's/^[^ ]+ //'}} * = `{echo $wi_event} diff --git a/cmd/wmii.sh.sh b/cmd/wmii.sh.sh @@ -86,10 +86,6 @@ _wi_script() { _wi_text() { cat <<'!' -Event Start - if [ "$1" = "$wmiiscript" ]; then - exit - fi Event Key Key "$@" ! @@ -188,6 +184,12 @@ wi_selclient() { wmiir read /client/sel/ctl | sed 1q | tr -d '\012' } +wi_nexttag() { + awk -v curtag=$(wi_seltag) ' + NR==1 {first = $0} + $0==curtag { if(getline) print $0; else print first; exit }' +} + wi_eventloop() { echo "$Keys" | wmiir write /keys @@ -201,6 +203,8 @@ wi_eventloop() { unset IFS set -- $wi_event event=$1; shift + [ "$event" = Start -a "$1" = "$wmiiscript" ] && + exit ( Event $event "$@" ) done true diff --git a/cmd/wmii/bar.c b/cmd/wmii/bar.c @@ -194,34 +194,6 @@ bar_draw(WMScreen *s) { copyimage(s->barwin, r, disp.ibuf, ZP); } -void -bar_load(Bar *b) { - IxpMsg m; - char *p, *q; - - p = b->buf; - m = ixp_message(p, strlen(p), 0); - - if(!waserror()) { /* Ignore errors. */ - msg_parsecolors(&m, &b->col); - poperror(); - } - - q = (char*)m.end-1; - while(q >= (char*)m.pos && *q == '\n') - *q-- = '\0'; - - q = b->text; - utflcpy(q, (char*)m.pos, sizeof b->text); - - p[0] = '\0'; - strlcat(p, b->col.colstr, sizeof b->buf); - strlcat(p, " ", sizeof b->buf); - strlcat(p, b->text, sizeof b->buf); - - bar_draw(b->screen); -} - Bar* bar_find(Bar *bp, const char *name) { Bar *b; diff --git a/cmd/wmii/dat.h b/cmd/wmii/dat.h @@ -303,7 +303,8 @@ struct View { #endif /* global variables */ -EXTERN struct { +typedef struct Defs Defs; +EXTERN struct Defs { CTuple focuscolor; CTuple normcolor; Font* font; diff --git a/cmd/wmii/fns.h b/cmd/wmii/fns.h @@ -69,7 +69,6 @@ void bar_destroy(Bar**, Bar*); void bar_draw(WMScreen*); Bar* bar_find(Bar*, const char*); void bar_init(WMScreen*); -void bar_load(Bar*); void bar_resize(WMScreen*); void bar_sety(WMScreen*, int); void bar_setbounds(WMScreen*, int, int); @@ -210,6 +209,7 @@ void spawn_command(const char*); /* message.c */ char* mask(char**, int*, int*); +char* message_bar(Bar*, IxpMsg*); char* message_client(Client*, IxpMsg*); char* message_root(void*, IxpMsg*); char* message_view(View*, IxpMsg*); @@ -219,6 +219,7 @@ char* msg_getword(IxpMsg*, char*); void msg_parsecolors(IxpMsg*, CTuple*); char* msg_selectarea(Area*, IxpMsg*); char* msg_sendclient(View*, IxpMsg*, bool swap); +char* readctl_bar(Bar*); char* readctl_client(Client*); char* readctl_root(void); char* readctl_view(View*); diff --git a/cmd/wmii/fs.c b/cmd/wmii/fs.c @@ -123,6 +123,28 @@ static IxpDirtab* dirtab[] = { [FsDTag] = dirtab_tag, }; typedef char* (*MsgFunc)(void*, IxpMsg*); +typedef char* (*BufFunc)(void*); + +typedef struct ActionTab ActionTab; +static struct ActionTab { + MsgFunc msg; + BufFunc read; + size_t buffer; + size_t size; + int max; +} actiontab[] = { + [FsFBar] = { .msg = (MsgFunc)message_bar, .read = (BufFunc)readctl_bar }, + [FsFCctl] = { .msg = (MsgFunc)message_client, .read = (BufFunc)readctl_client }, + [FsFRctl] = { .msg = (MsgFunc)message_root, .read = (BufFunc)readctl_root }, + [FsFTctl] = { .msg = (MsgFunc)message_view, .read = (BufFunc)readctl_view }, + [FsFTindex] = { .msg = (MsgFunc)0, .read = (BufFunc)view_index }, + [FsFColRules] = { .buffer = offsetof(Ruleset, string), .size = offsetof(Ruleset, size) }, + [FsFKeys] = { .buffer = offsetof(Defs, keys), .size = offsetof(Defs, keyssz) }, + [FsFRules] = { .buffer = offsetof(Ruleset, string), .size = offsetof(Ruleset, size) }, + [FsFClabel] = { .buffer = offsetof(Client, name), .max = sizeof ((Client*)0)->name }, + [FsFCtags] = { .buffer = offsetof(Client, tags), .max = sizeof ((Client*)0)->tags }, + [FsFprops] = { .buffer = offsetof(Client, props), .max = sizeof ((Client*)0)->props }, +}; void event(const char *format, ...) { @@ -335,6 +357,9 @@ lookup_file(IxpFileId *parent, char *name) case FsFColRules: file->p.rule = &def.colrules; break; + case FsFKeys: + file->p.ref = &def; + break; case FsFRules: file->p.rule = &def.rules; break; @@ -374,21 +399,19 @@ fs_walk(Ixp9Req *r) { static uint fs_size(IxpFileId *f) { - switch(f->tab.type) { - default: - return 0; - case FsFColRules: - case FsFRules: - return f->p.rule->size; - case FsFKeys: - return def.keyssz; - case FsFCtags: - return strlen(f->p.client->tags); - case FsFClabel: - return strlen(f->p.client->name); - case FsFprops: - return strlen(f->p.client->props); - } + ActionTab *t; + + t = &actiontab[f->tab.type]; + if(f->tab.type < nelem(actiontab)) + if(t->size) + return structmember(f->p.ref, int, t->size); + else if(t->buffer && t->max) + return strlen(structptr(f->p.ref, char, t->buffer)); + else if(t->buffer) + return strlen(structmember(f->p.ref, char*, t->buffer)); + else if(t->read) + return strlen(t->read(f->p.ref)); + return 0; } void @@ -422,9 +445,11 @@ void fs_read(Ixp9Req *r) { char *buf; IxpFileId *f; - int n; + ActionTab *t; + int n, found; f = r->fid->aux; + found = 0; if(!ixp_srv_verifyfile(f, lookup_file)) { ixp_respond(r, Enofile); @@ -440,53 +465,26 @@ fs_read(Ixp9Req *r) { ixp_pending_respond(r); return; } - switch(f->tab.type) { - case FsFprops: - ixp_srv_readbuf(r, f->p.client->props, strlen(f->p.client->props)); - ixp_respond(r, nil); - return; - case FsFColRules: - case FsFRules: - ixp_srv_readbuf(r, f->p.rule->string, f->p.rule->size); - ixp_respond(r, nil); - return; - case FsFKeys: - ixp_srv_readbuf(r, def.keys, def.keyssz); - ixp_respond(r, nil); - return; - case FsFCtags: - ixp_srv_readbuf(r, f->p.client->tags, strlen(f->p.client->tags)); - ixp_respond(r, nil); - return; - case FsFClabel: - ixp_srv_readbuf(r, f->p.client->name, strlen(f->p.client->name)); - ixp_respond(r, nil); - return; - case FsFBar: - ixp_srv_readbuf(r, f->p.bar->buf, strlen(f->p.bar->buf)); - ixp_respond(r, nil); - return; - case FsFRctl: - buf = readctl_root(); - ixp_srv_readbuf(r, buf, strlen(buf)); - ixp_respond(r, nil); - return; - case FsFCctl: - buf = readctl_client(f->p.client); - ixp_srv_readbuf(r, buf, strlen(buf)); - ixp_respond(r, nil); - return; - case FsFTindex: - buf = view_index(f->p.view); - ixp_srv_readbuf(r, buf, strlen(buf)); - ixp_respond(r, nil); - return; - case FsFTctl: - buf = readctl_view(f->p.view); - n = strlen(buf); + t = &actiontab[f->tab.type]; + if(f->tab.type < nelem(actiontab)) { + if(t->read) + buf = t->read(f->p.ref); + else if(t->buffer && t->max) + buf = structptr(f->p.ref, char, t->buffer); + else if(t->buffer) + buf = structmember(f->p.ref, char*, t->buffer); + else + goto done; + n = t->size ? structmember(f->p.ref, int, t->size) : strlen(buf); ixp_srv_readbuf(r, buf, n); ixp_respond(r, nil); - return; + found++; + } + done: + switch(f->tab.type) { + default: + if(found) + return; } } /* This should not be called if the file is not open for reading. */ @@ -495,12 +493,13 @@ fs_read(Ixp9Req *r) { void fs_write(Ixp9Req *r) { - MsgFunc mf; IxpFileId *f; + ActionTab *t; char *errstr; - char *p; - uint i; + int found; + found = 0; + errstr = nil; if(r->ifcall.io.count == 0) { ixp_respond(r, nil); return; @@ -517,25 +516,30 @@ fs_write(Ixp9Req *r) { return; } - switch(f->tab.type) { - case FsFColRules: - case FsFRules: - ixp_srv_writebuf(r, &f->p.rule->string, &f->p.rule->size, 0); - ixp_respond(r, nil); - break; - case FsFKeys: - ixp_srv_writebuf(r, &def.keys, &def.keyssz, 0); + t = &actiontab[f->tab.type]; + if(f->tab.type < nelem(actiontab)) { + if(t->msg) { + errstr = ixp_srv_writectl(r, t->msg); + r->ofcall.io.count = r->ifcall.io.count; + } + else if(t->buffer && t->max) + ixp_srv_writebuf(r, (char*[]){ structptr(f->p.ref, char, t->buffer) }, + t->size ? structptr(f->p.ref, uint, t->size) : nil, + t->max); + else if(t->buffer) + ixp_srv_writebuf(r, structptr(f->p.ref, char*, t->buffer), + t->size ? structptr(f->p.ref, uint, t->size) : nil, + t->max); + else + goto done; ixp_respond(r, nil); - break; + found++; + } +done: + switch(f->tab.type) { case FsFClabel: - ixp_srv_data2cstring(r); - utfecpy(f->p.client->name, - f->p.client->name + sizeof client->name, - r->ifcall.io.data); frame_draw(f->p.client->sel); update_class(f->p.client); - r->ofcall.io.count = r->ifcall.io.count; - ixp_respond(r, nil); break; case FsFCtags: ixp_srv_data2cstring(r); @@ -543,28 +547,6 @@ fs_write(Ixp9Req *r) { r->ofcall.io.count = r->ifcall.io.count; ixp_respond(r, nil); break; - case FsFBar: - i = strlen(f->p.bar->buf); - p = f->p.bar->buf; - ixp_srv_writebuf(r, &p, &i, 279); - bar_load(f->p.bar); - r->ofcall.io.count = i - r->ifcall.io.offset; - ixp_respond(r, nil); - break; - case FsFCctl: - mf = (MsgFunc)message_client; - goto msg; - case FsFTctl: - mf = (MsgFunc)message_view; - goto msg; - case FsFRctl: - mf = (MsgFunc)message_root; - goto msg; - msg: - errstr = ixp_srv_writectl(r, mf); - r->ofcall.io.count = r->ifcall.io.count; - ixp_respond(r, errstr); - break; case FsFEvent: if(r->ifcall.io.data[r->ifcall.io.count-1] == '\n') event("%.*s", (int)r->ifcall.io.count, r->ifcall.io.data); @@ -575,7 +557,8 @@ fs_write(Ixp9Req *r) { break; default: /* This should not be called if the file is not open for writing. */ - die("Write called on an unwritable file"); + if(!found) + die("Write called on an unwritable file"); } poperror(); return; @@ -652,7 +635,6 @@ fs_remove(Ixp9Req *r) { return; } - switch(f->tab.type) { default: ixp_respond(r, Enoperm); @@ -661,9 +643,12 @@ fs_remove(Ixp9Req *r) { s = f->p.bar->screen; bar_destroy(f->next->p.bar_p, f->p.bar); bar_draw(s); - ixp_respond(r, nil); + break; + case FsDClient: + client_kill(f->p.client, true); break; } + ixp_respond(r, nil); } void diff --git a/cmd/wmii/message.c b/cmd/wmii/message.c @@ -29,6 +29,7 @@ enum { LBORDER, LCLIENT, LCOLMODE, + LCOLORS, LDEBUG, LDOWN, LEXEC, @@ -42,6 +43,7 @@ enum { LGROW, LINCMODE, LKILL, + LLABEL, LLEFT, LNORMCOLORS, LNUDGE, @@ -68,6 +70,7 @@ char *symtab[] = { "border", "client", "colmode", + "colors", "debug", "down", "exec", @@ -81,6 +84,7 @@ char *symtab[] = { "grow", "incmode", "kill", + "label", "left", "normcolors", "nudge", @@ -472,6 +476,31 @@ getframe(View *v, int scrn, IxpMsg *m) { } char* +readctl_bar(Bar *b) { + bufclear(); + bufprint("colors %s\n", b->col.colstr); + bufprint("label %s\n", b->text); + return buffer; +} + +char* +message_bar(Bar *b, IxpMsg *m) { + + switch(getsym(msg_getword(m, nil))) { + case LCOLORS: + msg_parsecolors(m, &b->col); + break; + case LLABEL: + utflcpy(b->text, (char*)m->pos, sizeof b->text); + break; + default: + error(Ebadvalue); + } + bar_draw(b->screen); + return nil; +} + +char* readctl_client(Client *c) { bufclear(); bufprint("%#C\n", c); diff --git a/doc/wmii.tex b/doc/wmii.tex @@ -13,7 +13,12 @@ \usepackage{xcolor} \usepackage[xetex,breaklinks,colorlinks,linkcolor=black]{hyperref} -% Indexes +\let\EA=\expandafter + +\newif\ifexpandfragments +\newif\ifdefinefragments + +%% Indexes \makeindex \let\primary=\textbf @@ -26,36 +31,63 @@ \def\man#1#2{#2\textbf{(#1)}} -% Key specs +\makeatletter + +%% Key specs \def\key#1{{\small$\langle$\addfontfeature{Numbers=Lining}#1\/$\rangle$}} \let\<=< \catcode`\<=\active \def<#1>{\key{#1}} -% Display ‹...› and «...» as text in left and right pointing -% angle brackets. I use «» and ‹› because my terminal doesn't -% display left and right pointing angle brackets properly, and -% Xorg's compose maps don't provide them, anyway. +%% Display ‹...› and «...» as text in left and right pointing +%% angle brackets. I use «» and ‹› because my terminal doesn't +%% display left and right pointing angle brackets properly, and +%% Xorg's compose maps don't provide them, anyway. +\def\«{«}\def\‹{‹} \catcode`\«=\active \catcode`\‹=\active \def‹#1›{$\langle${\itshape#1}$\rangle$} \def«#1»{$\langle\langle${\itshape#1}$\rangle\rangle$} +\catcode`\∅=\active +\def∅{\box0} +\def«{% + \let\dofragment@target=\hyperlink% + \@ifnextchar*\dofragment@@\dofragment@} +\def\dofragment@@*{% + \let\dofragment@target=\hypertarget% + \dofragment@} +\def\dofragment@#1»{% + \setbox0=\hbox{$\langle\langle${\itshape#1}$\rangle\rangle$}% + \ifexpandfragments% + \def\a{\sp\sp\comment \boxzero^^J}% + \begingroup% + \def\ { }\xdef\@frag@name{#1}% + \endgroup% + \UseFragment{∅}\@frag@name% + \else% + \dofragment@target{frag:#1}{\box0}% + \fi} + % Display |...| as verbatim, teletype text. \DefineShortVerb{\|} -\makeatletter \let\idx@@heading\chapter -\let\:=: -\catcode`\:=\active -\def:{\@ifnextchar:{\coloncoloneq}{\:}} -\def\coloncoloneq#1{\@ifnextchar={$\Coloneqq$\coloncoloneqq}{\:\:}} -\def\coloncoloneqq#1{} - -% Create a verbatim {code} environment which highlights strings -% and comments. Several unicode characters are hacked to replace -% the grabbed characters, since we can't escape them in the -% verbatim environment. +\def\:{:} +\iffalse + \catcode`\:=\active + \gdef:{\@ifnextchar:{\coloncoloneq}{\:}} + \gdef\coloncoloneq#1{\@ifnextchar={$\Coloneqq$\coloncoloneqq}{\:\:}} + \gdef\coloncoloneqq#1{} +\fi +\def\≔{≔} +\catcode`\≔=\active +\def≔{\ensuremath{\Coloneqq}} + +%% Create a verbatim {code} environment which highlights strings +%% and comments. Several unicode characters are hacked to replace +%% the grabbed characters, since we can't escape them in the +%% verbatim environment. \colorlet{comment}{gray} \colorlet{string}{red!100!black!90} \let\‘=‘ @@ -67,17 +99,66 @@ \catcode`‘=\active \def“¶1”{{\color{string}\“¶1”}}% \def‘¶1’{{\color{string}\‘¶1’}}% +\def\comment{\itshape\color{comment}\let“=\“\let‘=\‘\#} +\def\docodes{\catcode`\#=\active\catcode`“=\active\catcode`‘=\active\catcode`\☺=0} +\def\dodefineactive{ + \let#=\comment + } \DefineVerbatimEnvironment{code}{Verbatim}{xleftmargin=2em,gobble=2,% - codes={\catcode`\#=\active\catcode`\:=\active\catcode`“=\active\catcode`‘=\active},% - defineactive={% - \def#{\itshape\color{comment}\let“=\“\let‘=\‘\#}% - }} + codes={\docodes},% + defineactive={\dodefineactive}} \catcode`\#=6 \catcode`“=12 \catcode`‘=12 -% Convenience defs for the various wmii commands, and a few -% others. +%% Save code fragments for piecing together later +\begingroup + \catcode`\@=0 + @catcode`\\=12 + @gdef@bcode{@detokenize{\begin{code}^^J}} + @gdef@ecode{@detokenize{\end{code}^^J}} + @catcode`@ =12@gdef@sp{ } +@endgroup + +% Ripped from fancyverb +% I'm currently rather unfond of it. +\def\Fragment{\FV@Environment{}{Fragment}} +\def\FVB@Fragment#1{% + \@bsphack + \begingroup + \FV@UseKeyValues + \gdef\Fragment@Name{#1}% + \xdef\Fragment@Prefix{\«*#1» \≔^^J} + \xdef\TheFragment{} + \def\FV@ProcessLine##1{% + \edef\frag{\detokenize{##1^^J}}% + \xdef\TheFragment{\TheFragment\frag}}% + \FV@Scan} +\def\FVE@Fragment{% + \EA\global\EA\let + \csname SV@\Fragment@Name\endcsname\TheFragment% + \endgroup% + \EA\UseFragment\EA{\Fragment@Prefix}\Fragment@Name} +\DefineVerbatimEnvironment{Fragment}{Fragment}{} + +\def\UseFragment#1#2{ + \begingroup + % \message{UseFragment #2^^J} + \EA\let\EA\a\csname SV@#2\endcsname + \ifx\a\undefined\def\a{\ldots}\fi + \ifx\FV@EnvironName\relax% + \edef\a{\bcode\detokenize{++#1}\a\ecode}\else% + \edef\a{\detokenize{#1}\a}\fi% + \newtoks\tokens + \EA\tokens\EA{\a} + \everyeof{\noexpand}% + % \EA\message\EA{\the\tokens} + \scantokens\EA{\the\tokens} + \endgroup +} + +%% Convenience defs for the various wmii commands, and a few +%% others. \def\wmii{\texttt{wmii}} \def\wiIXmenu{\texttt{wi9menu}} \def\wimenu{\texttt{wimenu}} @@ -125,7 +206,6 @@ This file is distributed under the same terms as wmii: \parindent=0pt \parskip=1em -\catcode`\:=12 Copyright © 2009 Kris Maglione <\href{mailto:maglione.k@gmail.com}{maglione.k@gmail.com}> Permission is hereby granted, free of charge, to any person obtaining a @@ -635,8 +715,7 @@ windows, and changes of focus and views. We'll start building our configuration with an event processing framework: -\begin{code} - «Event Loop» ::= +\begin{Fragment}{Event Loop} # Broadcast a custom event wmiir xwrite /event Start wmiirc @@ -657,13 +736,12 @@ framework: «Event Handlers» esac done -\end{code} +\end{Fragment} Now, we need to consider which types of events we'll need to handle: -\begin{code} - «Event Handlers» ::= +\begin{Fragment}{Event Handlers} «View Button Events» «Urgency Events» «Unresponsive Clients» @@ -671,37 +749,45 @@ handle: «Key Events» «Client Menu Events» «Tag Menu Events» -\end{code} +\end{Fragment} \section{Bar Items} The bar is described by the files in the two directories |/lbar/| and |/rbar/| for buttons on the left and right side of the bar, -respectively. The format of the files is: +respectively. The files act as control files (section +\ref{sec:controlfiles}) with the contents: \begin{code} - ‹Color Tuple› ‹Label› + color ‹Color Tuple› + label ‹Label› \end{code} -although the color tuple may be elided in cases where the label -doesn't match its format. - A ‹Color Tuple› is defined as: \begin{code} - ‹tuple› ::= ‹foreground color› ‹background color› ‹border color› - ‹color› ::= #‹6 character RGB hex color code› + ‹Color Tuple› ≔ ‹foreground color› ‹background color› ‹border color› + ‹* Color› ≔ ‹RGB color› | ‹RGBA color› + ‹RGB color› ≔ #‹6 character RGB hex color code› + ‹RGBA color› ≔ rgba:‹red›/‹green›/‹blue›/‹alpha› \end{code} +\noindent +where all of the colors are represented as lowercase, +hexidecimal values. In the case of RGBA colors, they may be 1--4 +characters long, though they will be standardized internally to +2 characters. + +\medskip + Let's define our basic theme information now: -\begin{code} - «Theme Definitions» ::= +\begin{Fragment}{Theme Definitions} normcolors=‘#000000 #c1c48b #81654f’ focuscolors=‘#000000 #81654f #000000’ background=‘#333333’ font=‘drift,-*-fixed-*-*-*-*-9-*-*-*-*-*-*-*’ -\end{code} +\end{Fragment} \subsection{View Buttons} @@ -712,8 +798,7 @@ our view event handlers: \index{events!DestroyTag} \index{events!FocusTag} \index{events!UnfocusTag} -\begin{code} - «View Button Events» ::= +\begin{Fragment}{View Button Events} CreateTag) # CreateTag ‹Tag Name› echo $normcolors $1 | wmiir create /lbar/$1;; DestroyTag) # DestroyTag ‹Tag Name› @@ -722,7 +807,7 @@ our view event handlers: wmiir xwrite /lbar/$1 $focuscolors $1;; UnfocusTag) # UnfocusTag ‹Tag Name› wmiir xwrite /lbar/$1 $normcolors $1;; -\end{code} +\end{Fragment} \subsection{Urgency} @@ -732,13 +817,12 @@ Windows can specify that they require attention, and in X11 parlance, this is called urgency. When a window requests attention as such, or declares that it's been satisfied, \wmii\ broadcasts an event for the client and an event for each view -that it belongs to, and fills in the client's layout box. It's -the job of a script to decide how to handle it above and beyond -that. The standard scripts simply mark urgent views with an -asterisk: +that it belongs to. It also fills in the layout box of any +client deemed urgent. It's the job of a script to decide how to +handle urgency events above and beyond that basic measure. The +standard scripts simply mark urgent views with an asterisk: -\begin{code} - «Urgency Events» ::= +\begin{Fragment}{Urgency Events} # The urgency events are ‘Client’ events when the program # owning the window sets its urgency state. They're ‘Manager’ # events when wmii or the wmii user sets the state. @@ -746,7 +830,7 @@ asterisk: wmiir xwrite /lbar/$2 $2;; NotUrgentTag) # NotUrgentTag ‹‘Client’ or ‘Manager’› ‹Tag Name› wmiir xwrite /lbar/$2 $2;; -\end{code} +\end{Fragment} \index{events!UrgentTag|)} \index{events!NotUrgentTag|)} @@ -756,18 +840,17 @@ The standard scripts provide a custom Notice event for displaying status information. The events appear in the long bar between the left and right sides for five seconds. -\begin{code} - «Notice Events» ::= +\begin{Fragment}{Notice Events} Notice) wmiir xwrite /rbar/!notice $line kill $xpid 2>/dev/null # Let's hope this isn't reused... { sleep 5; wmiir xwrite /rbar/!notice ‘ ’; } & xpid = $!;; -\end{code} +\end{Fragment} \section{Keys} -\label{keybindings} +\label{sec:keybindings} \index{key bindings} \index{filesystem!/!keys} \index{filesystem!/!event} @@ -798,8 +881,7 @@ Examples of key bindings: Now, let's bind the keys we plan on using: -\begin{code} - «Bind Keys» ::= +\begin{Fragment}{Bind Keys} { cat <<! Mod4-space @@ -828,12 +910,11 @@ Now, let's bind the keys we plan on using: echo Mod4-Shift-$i done } | wmiir write /keys -\end{code} +\end{Fragment} and lay a framework for processing their events: -\begin{code} - «Key Events» ::= +\begin{Fragment}{Key Events} Key) # Key ‹Key Name› case $1 in «Motion Keys» @@ -844,7 +925,7 @@ and lay a framework for processing their events: «Tag Selection Keys» «Tagging Keys» esac;; -\end{code} +\end{Fragment} \section{Click Menus} @@ -853,15 +934,16 @@ reach for the keyboard. To help cope, \wmii\ provides a mouse-driven, single-click menu. The default configuration uses it for client and tag menus. -\begin{code} - «Click Menu Initialization» ::= +\begin{Fragment}{Click Menu Initialization} clickmenu() { if res=$(wmii9menu -- “$@”); then eval “$res”; fi } -\end{code} +\end{Fragment} \section{Control Files} +\label{sec:controlfiles} + Several directories including the root, have control files, named |ctl|. These files are used to control the object (e.g., a client or tag) represented by the directory. Each line of the @@ -937,7 +1019,10 @@ client. The files in these directories are: \item[pid] Read-only value of the PID of the program that owns the window, if the value is available and the process is on the same machine as wmii. - \item[slay] When written, the client is killed peremptorily. + \item[slay] When written, the client is disconnected + peremptorily. If the client's PID is available and the + process is the same machine as wmii, its parent process + is killed \item[tags] The client's tags. The same as the tags file. \item[urgent] The client's urgency state. When |on|, the client's layout box will be highlighted. Possible values @@ -953,19 +1038,21 @@ client. The files in these directories are: \item[tags] \index{filesystem!/client/*/@\clientlabel!tags} The client's tags. Tag names are separated by |+|, |-|, or - |^| signs. Tags beginning and ending with |/| are treated as - regular expressions, which place the client on any extant - matching tag\footnote{While a client with a regex tag will - always appear in all matching views, it will not keep those - views in existence. When the last client explicitly tagged - with a view is removed, the view is deleted as soon as it - becomes inactive.}. If the written value begins with a |+|, - |-|, or |^|, the tags are updated rather than overwritten. - Tag names which directly follow a |-| sign are removed - rather than added, while those following a |^| are toggled. - Regular expression tags which directly follow a minus sign - are treated as exclusion expressions. For example, the tag - string |+/foo/-/food/| will match the tag + |^| signs. Tag names which directly follow a |+| sign are + added, while whose following a |-| sign are removed and + those following a |^| are toggled. If the value written + begins with one of these characters, the value is appended + to the clients tags rather than replacing them. + + Tags formatted as |/‹regex›/| are treated as regular + expressions, which place the client on any extant matching + tag\footnote{While a client with a regex tag will always + appear in all matching views, it will not keep those views + in existence. When the last client explicitly tagged with a + view is removed, the view is deleted as soon as it becomes + inactive.}. Regular expression tags which directly follow a + minus sign are treated as exclusion expressions. For + example, the tag string |+/foo/-/food/| will match the tag |foobar|, but not the tag |foodstand|. \end{description} @@ -975,16 +1062,14 @@ client. The files in these directories are: To control clients, we'll add the following key bindings: -\begin{code} - «Client Command Keys» ::= +\begin{Fragment}{Client Command Keys} Mod4-Shift-c) wmiir xwrite /client/sel/ctl kill;; Mod4-f) wmiir xwrite /client/sel/ctl Fullscreen toggle;; -\end{code} +\end{Fragment} And to manage their tags, we'll need: -\begin{code} - «Tagging Keys» ::= +\begin{Fragment}{Tagging Keys} Mod4-Shift-t) # Get the selected client's id c=$(wmiir read /client/sel/ctl | sed 1q) @@ -994,19 +1079,18 @@ And to manage their tags, we'll need: wmiir xwrite /client/$c/tags $tag;; Mod4-Shift-[0-9]) wmiir xwrite /client/sel/tags ${1##*-};; -\end{code} +\end{Fragment} \subsection{Click Menus} \index{events!ClientMouseDown} -\begin{code} - «Client Menu Events» ::= +\begin{Fragment}{Client Menu Events} ClientMouseDown) # ClientMouseDown ‹Client ID› ‹Button› [ $2 = 3 ] && clickmenu \ “Delete:wmiir xwrite /client/$1/ctl kill” \ “Kill: wmiirxwrite /client/$1/ctl slay” \ “Fullscreen:wmiir xwrite /client/$1/ctl fullscreen on” -\end{code} +\end{Fragment} \subsection{Unresponsive Clients} @@ -1015,8 +1099,7 @@ When \wmii\ tries to close a window, it waits 8 seconds for the client to respond, and then lets its scripts decide what to do with it. The stock scripts prompt the user for input: -\begin{code} - «Unresponsive Clients» ::= +\begin{Fragment}{Unresponsive Clients} UnresponsiveClient) # UnresponsiveClient ‹Client ID› { # Use wihack to make the xmessage a transient window of @@ -1029,7 +1112,7 @@ with it. The stock scripts prompt the user for input: $(wmiir read /client/$1/label)) [ $resp = Kill ] && wmiir xwrite /client/$1/ctl slay } &;; -\end{code} +\end{Fragment} \index{events!UnresponsiveClient|)} \section{Views} @@ -1117,36 +1200,36 @@ in these directories are: We'll use the following key bindings to interact with views: -\begin{code} - «Motion Keys» ::= +\begin{Fragment}{Motion Keys} Mod4-h) wmiir xwrite /tag/sel/ctl select left;; Mod4-l) wmiir xwrite /tag/sel/ctl select right;; Mod4-k) wmiir xwrite /tag/sel/ctl select up;; Mod4-j) wmiir xwrite /tag/sel/ctl select down;; Mod4-space) wmiir xwrite /tag/sel/ctl select toggle;; +\end{Fragment} - «Client Movement Keys» ::= +\begin{Fragment}{Client Movement Keys} Mod4-Shift-h) wmiir xwrite /tag/sel/ctl send sel left;; Mod4-Shift-l) wmiir xwrite /tag/sel/ctl send sel right;; Mod4-Shift-k) wmiir xwrite /tag/sel/ctl send sel up;; Mod4-Shift-j) wmiir xwrite /tag/sel/ctl send sel down;; Mod4-Shift-space) wmiir xwrite /tag/sel/ctl send sel toggle;; +\end{Fragment} - «Column Mode Keys» ::= +\begin{Fragment}{Column Mode Keys} Mod4-d) wmiir xwrite /tag/sel/ctl colmode sel -stack-max;; Mod4-s) wmiir xwrite /tag/sel/ctl colmode sel stack-max;; Mod4-m) wmiir xwrite /tag/sel/ctl colmode sel stack+max;; -\end{code} +\end{Fragment} \subsection{Click Menus} \index{events!LeftBarMouseDown} -\begin{code} - «Tag Menu Events» ::= +\begin{Fragment}{Tag Menu Events} LeftBarMouseDown) # LeftBarMouseDown ‹Button› ‹Bar Name› [ $1 = 3 ] && clickmenu \ “Delete:delete_view $2” -\end{code} +\end{Fragment} \section{Command and Program Execution} @@ -1160,28 +1243,26 @@ commands. We use |wmiir setsid| to launch programs with their own session IDs to prevent untoward effects when this script dies. -\begin{code} - «Command Execution Initialization» ::= +\begin{Fragment}{Command Execution Initialization} terminal() { wmiir setsid xterm “$@” } proglist() { IFS=: wmiir proglist $1 | sort | uniq unset IFS } -\end{code} +\end{Fragment} \subsection{Key Bindings} -\begin{code} - «Command Execution Keys» ::= +\begin{Fragment}{Command Execution Keys} Mod4-Return) terminal & ;; - Mod4-p) eval exec wmiir setsid "$(proglist $PATH | wimenu)" &;; + Mod4-p) eval exec wmiir setsid “$(proglist $PATH | wimenu)” &;; Mod4-a) { set -- $(proglist $WMII_CONFPATH | wimenu) which=$(which which) prog=$(PATH=$WMII_CONFPATH $which $1); shift eval exec $prog “$@” } &;; -\end{code} +\end{Fragment} \section{The Root} @@ -1243,9 +1324,9 @@ The root filesystem contains the following: searched for the executable. Otherwise, the whole argument is passed to the shell for evaluation. \end{description} - \item[keys] The global keybindings. See section \ref{keybindings}. + \item[keys] The global keybindings. See section \ref{sec:keybindings}. \index{filesystem!/!keys|primary} - \item[event] The global event feed. See section \ref{keybindings}. + \item[event] The global event feed. See section \ref{sec:keybindings}. \index{filesystem!/!event|primary} \item[colrules] \index{filesystem!/!colrules} @@ -1260,7 +1341,7 @@ The root filesystem contains the following: Where, \begin{code} - ‹width› := ‹percent of screen› | ‹pixels›px + ‹width› ≔ ‹percent of screen› | ‹pixels›px \end{code} When a new column, ‹n›, is created on a view whose name @@ -1306,8 +1387,7 @@ The root filesystem contains the following: We'll need to let \wmii\ know about our previously defined theme information: -\begin{code} - «Configuration» ::= +\begin{Fragment}{Configuration} «Theme Definitions» xsetroot -solid $background @@ -1318,14 +1398,13 @@ information: font $font grabmod Mod4 ! -\end{code} +\end{Fragment} \subsection{Key Bindings} And we need a few more key bindings to select our views: -\begin{code} - «Tag Selection Keys» ::= +\begin{Fragment}{Tag Selection Keys} Mod4-t) # Prompt the user for a tag tags=$(wmiir ls /tag | sed ‘s,/,,; /^sel$/d’ | wimenu) @@ -1333,7 +1412,7 @@ And we need a few more key bindings to select our views: wmiir xwrite /ctl view $tags;; Mod4-[0-9]) wmiir xwrite /ctl view ${1##*-};; -\end{code} +\end{Fragment} \section{Tieing it All Together} @@ -1501,7 +1580,7 @@ For clarity, here is the end result: # «Command Execution Keys» Mod4-Return) terminal & ;; - Mod4-p) eval exec wmiir setsid "$(proglist $PATH | wimenu)" &;; + Mod4-p) eval exec wmiir setsid “$(proglist $PATH | wimenu)” &;; Mod4-a) { set -- $(proglist $WMII_CONFPATH | wimenu) prog=$(PATH=$WMII_CONFPATH which $1); shift diff --git a/include/stuff/base.h b/include/stuff/base.h @@ -17,8 +17,10 @@ #ifndef offsetof # define offsetof(type, member) ((size_t)&((type*)0)->member) #endif +#define structptr(ptr, type, offset) \ + ((type*)((char*)(ptr) + (offset))) #define structmember(ptr, type, offset) \ - (*(type*)((char*)(ptr) + (offset))) + (*structptr(ptr, type, offset)) #undef uchar #undef ushort diff --git a/man/wmii.man1 b/man/wmii.man1 @@ -157,6 +157,8 @@ key binding quick-reference. | Mod-k | Move to a window _above_ the one currently focused | Mod-space | Toggle between the managed and floating layers | Mod-t <tag> | Move to the view of the given <tag> +| Mod-n | Move to the next view +| Mod-b | Move to the previous view | Mod-//[0-9]// | Move to the view with the given number === Moving Things Around === @@ -473,12 +475,9 @@ under '/rbar/' appear on the right, with the leftmost item occupying all extra available space. The items are sorted lexicographically. -The files may be read to obtain the colors and text of the bars. -The colors are at the beginning of the string, represented as a -tuple of 3 hex color codes for the foreground, background, and -border, respectively. When writing the bar files, the colors may -be omitted if the text would not otherwise appear to contain -them. +The files may be read or written to obtain or alter the colors +and text of the bars. The format is similar to the various _ctl_ +files and should be self explanitory. = FILES = diff --git a/rc/wmiirc.sh b/rc/wmiirc.sh @@ -65,7 +65,7 @@ wmiir write /rules <<! # Status Bar Info status() { - echo -n $(uptime | sed 's/.*://; s/,//g') '|' $(date) + echo -n label $(uptime | sed 's/.*://; s/,//g') '|' $(date) } # Generic overridable startup details @@ -75,26 +75,26 @@ local_events() { true;} wi_runconf -s wmiirc_local startup -echo $WMII_NORMCOLORS | wmiir create $noticebar +echo colors $WMII_NORMCOLORS | wmiir create $noticebar # Event processing events() { cat <<'!' # Events Event CreateTag - echo "$WMII_NORMCOLORS" "$@" | wmiir create "/lbar/$@" + echo colors "$WMII_NORMCOLORS$wi_newline" label "$@" | wmiir create "/lbar/$@" Event DestroyTag wmiir remove "/lbar/$@" Event FocusTag - wmiir xwrite "/lbar/$@" "$WMII_FOCUSCOLORS" "$@" + wmiir xwrite "/lbar/$@" colors "$WMII_FOCUSCOLORS" Event UnfocusTag - wmiir xwrite "/lbar/$@" "$WMII_NORMCOLORS" "$@" + wmiir xwrite "/lbar/$@" colors "$WMII_NORMCOLORS" Event UrgentTag shift - wmiir xwrite "/lbar/$@" "*$@" + wmiir xwrite "/lbar/$@" label "*$@" Event NotUrgentTag shift - wmiir xwrite "/lbar/$@" "$@" + wmiir xwrite "/lbar/$@" label "$@" Event LeftBarClick LeftBarDND shift wmiir xwrite /ctl view "$@" @@ -129,19 +129,12 @@ Event ClientMouseDown Menu LBar-3-Delete tag=$1; clients=$(wmiir read "/tag/$tag/index" | awk '/[^#]/{print $2}') for c in $clients; do - if [ "$tag" = "$(wmiir read /client/$c/tags)" ]; then - wmiir xwrite /client/$c/ctl kill - else - wmiir xwrite /client/$c/tags -$tag - fi - if [ "$tag" = "$(wi_seltag)" ]; then - newtag=$(wi_tags | awk -v't='$tag ' - $1 == t { if(!l) getline l - print l - exit } - { l = $0 }') - wmiir xwrite /ctl view $newtag + if [ "$tag" = "$(wmiir read /client/$c/tags)" ] + then wmiir xwrite /client/$c/ctl kill + else wmiir xwrite /client/$c/tags -$tag fi + [ "$tag" = "$(wi_seltag)" ] && + wmiir xwrite /ctl view $(wi_tags | wi_nexttag) done Event LeftBarMouseDown wi_fnmenu LBar "$@" & @@ -160,7 +153,7 @@ Action status if wmiir remove /rbar/status 2>/dev/null; then sleep 2 fi - echo "$WMII_NORMCOLORS" | wmiir create /rbar/status + echo colors "$WMII_NORMCOLORS" | wmiir create /rbar/status while status | wmiir write /rbar/status; do sleep 1 done @@ -238,6 +231,10 @@ Key $MODKEY-t # Change to another tag Key $MODKEY-Shift-t # Retag the selected client # Assumes left-to-right order of evaluation wmiir xwrite /client/$(wi_selclient)/tags $(wi_tags | wimenu -h "${hist}.tags" -n 50) & +Key $MODKEY-n # Move to the next tag + wmiir xwrite /ctl view $(wi_tags | wi_nexttag) +Key $MODKEY-b # Move to the previous tag + wmiir xwrite /ctl view $(wi_tags | sort -r | wi_nexttag) ! for i in 0 1 2 3 4 5 6 7 8 9; do cat <<! @@ -273,9 +270,11 @@ unset IFS wi_tags | while read tag do if [ "$tag" = "$seltag" ]; then - echo "$WMII_FOCUSCOLORS" "$tag" + echo colors "$WMII_FOCUSCOLORS" + echo label $tag else - echo "$WMII_NORMCOLORS" "$tag" + echo colors "$WMII_NORMCOLORS" + echo label $tag fi | wmiir create "/lbar/$tag" done