[menu] Add vertical mode.

This commit is contained in:
Kris Maglione 2010-10-07 16:31:41 -04:00
parent 8ca9f3ca3a
commit ed809b8471
27 changed files with 412 additions and 477 deletions

View File

@ -29,14 +29,14 @@ def message(message):
call(*args, input=message)
def program_list(path):
names = []
names = set()
for d in path:
try:
for f in os.listdir(d):
p = '%s/%s' % (d, f)
if f not in names and os.access(p, os.X_OK) and (
os.path.isfile(p) or os.path.islink(p)):
names.append(f)
if (f not in names and os.access(p, os.X_OK) and
os.path.isfile(p)):
names.add(f)
except Exception:
pass
return sorted(names)

View File

@ -5,12 +5,13 @@ include $(ROOT)/mk/wmii.mk
main.c: $(ROOT)/mk/wmii.mk
bindings.c: keys.txt Makefile
( echo "char binding_spec[] = "; \
( echo "char binding_spec[] ="; \
sed 's/.*/ "&\\n"/' keys.txt; \
echo " ;" ) >bindings.c
echo " ;" ) >$@
TARG = wimenu
HFILES= dat.h fns.h
TAGFILES= dat.h
PACKAGES += $(X11PACKAGES)

View File

@ -69,9 +69,7 @@ caret_find(int dir, int type) {
p = next;
return p;
case CHAR:
if(p < end)
return p+1;
return p;
return next_rune(p, &r);
}
}
else if(dir == BACKWARD) {
@ -88,9 +86,7 @@ caret_find(int dir, int type) {
p = next;
return p;
case CHAR:
if(p > end)
return prev_rune(end, p, &r);
return end;
return prev_rune(end, p, &r);
}
}
input.pos_end = nil;

View File

@ -11,8 +11,6 @@
#include <stuff/x.h>
#include <stuff/util.h>
#define BLOCK(x) do { x; }while(0)
#ifndef EXTERN
# define EXTERN extern
#endif
@ -69,38 +67,40 @@ EXTERN struct {
int filter_start;
} input;
EXTERN struct {
Window* win;
Image* buf;
char* prompt;
int height;
int rows;
bool ontop;
Rectangle itemr;
Point arrow;
} menu;
extern char binding_spec[];
EXTERN int numlock;
EXTERN long xtime;
EXTERN Image* ibuf;
EXTERN Font* font;
EXTERN CTuple cnorm, csel;
EXTERN bool ontop;
EXTERN Cursor cursor[1];
EXTERN Visual* render_visual;
EXTERN IxpServer srv;
EXTERN Window* barwin;
EXTERN struct {
Item* all;
Item* first;
Item* start;
Item* end;
Item* sel;
int maxwidth;
} match;
EXTERN Item* items;
EXTERN Item* matchfirst;
EXTERN Item* matchstart;
EXTERN Item* matchend;
EXTERN Item* matchidx;
Font* font;
CTuple cnorm;
CTuple csel;
EXTERN Item hist;
EXTERN Item* histidx;
EXTERN Item* histsel;
EXTERN int maxwidth;
EXTERN int itempad;
EXTERN int result;
EXTERN char* (*find)(const char*, const char*);
EXTERN int (*compare)(const char*, const char*, size_t);
EXTERN char* prompt;
EXTERN int promptw;
EXTERN char* (*find)(const char*, const char*);
EXTERN int (*compare)(const char*, const char*, size_t);

View File

@ -19,25 +19,25 @@ history_search(int dir, char *string, int n) {
Item *i;
if(dir == FORWARD) {
if(histidx == &hist)
if(histsel == &hist)
return hist.string;
for(i=histidx->next; i != hist.next; i=i->next)
for(i=histsel->next; i != hist.next; i=i->next)
if(!i->string || !compare(i->string, string, n)) {
histidx = i;
histsel = i;
return i->string;
}
return string;
}
assert(dir == BACKWARD);
if(histidx == &hist) {
if(histsel == &hist) {
free(hist.string);
hist.string = estrdup(input.string);
}
for(i=histidx->prev; i != &hist; i=i->prev)
for(i=histsel->prev; i != &hist; i=i->prev)
if(!compare(i->string, string, n)) {
histidx = i;
histsel = i;
return i->string;
}
return string;

View File

@ -13,7 +13,8 @@ struct Key {
char** action;
};
static Key* bindings;
static Key* bindings;
static int numlock;
/*
* To do: Find my red black tree implementation.

View File

@ -1,8 +1,6 @@
/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#define IXP_NO_P9_
#define IXP_P9_STRUCTS
#define EXTERN
#include "dat.h"
#include <X11/Xproto.h>
@ -23,7 +21,9 @@ static int screen_hint;
static void
usage(void) {
fatal("usage: wimenu -i [-h <history>] [-a <address>] [-p <prompt>] [-s <screen>]\n");
fprint(2, "usage: %s -i [-a <address>] [-h <history>] [-p <prompt>] [-r <rows>] [-s <screen>]\n", argv0);
fprint(2, " See manual page for full usage details.\n");
exit(1);
}
static int
@ -50,13 +50,13 @@ populate_list(Biobuf *buf, bool hist) {
bool stop;
stop = !hist && !isatty(buf->fid);
ret.next_link = nil;
i = &ret;
while((p = Brdstr(buf, '\n', true))) {
if(stop && p[0] == '\0')
break;
link(i, emallocz(sizeof *i));
i->next_link = i->next;
i = i->next;
i->next_link = emallocz(sizeof *i);
i = i->next_link;
i->string = p;
i->retstring = p;
if(cmdsep && (p = strstr(p, cmdsep))) {
@ -65,15 +65,12 @@ populate_list(Biobuf *buf, bool hist) {
}
if(!hist) {
i->len = strlen(i->string);
i->width = textwidth_l(font, i->string, i->len);
if(i->width > maxwidth)
maxwidth = i->width;
i->width = textwidth_l(font, i->string, i->len) + itempad;
match.maxwidth = max(i->width, match.maxwidth);
}
}
link(i, &ret);
splice(&ret);
return ret.next != &ret ? ret.next : nil;
return ret.next_link;
}
static void
@ -86,7 +83,7 @@ check_competions(IxpConn *c) {
return;
}
input.filter_start = strtol(s, nil, 10);
items = populate_list(cmplbuf, false);
match.all = populate_list(cmplbuf, false);
update_filter(false);
menu_draw();
}
@ -143,8 +140,8 @@ update_filter(bool print) {
if(input.pos < input.end)
filter = freelater(estrndup(filter, input.pos - filter));
matchidx = nil;
matchfirst = matchstart = filter_list(items, filter);
match.sel = nil;
match.first = match.start = filter_list(match.all, filter);
if(print)
update_input();
}
@ -158,8 +155,7 @@ init_screens(void) {
int i, n;
rects = xinerama_screens(&n);
if (screen_hint >= 0 && screen_hint < n)
/* We were given a valid screen index, use that. */
if(screen_hint >= 0 && screen_hint < n)
i = screen_hint;
else {
/* Pick the screen with the pointer, for now. Later,
@ -178,11 +174,11 @@ init_screens(void) {
int
main(int argc, char *argv[]) {
Item *item;
static char *address;
static char *histfile;
static char *keyfile;
static bool nokeys;
Item *item;
int i;
long ndump;
@ -220,7 +216,10 @@ main(int argc, char *argv[]) {
ndump = strtol(EARGF(usage()), nil, 10);
break;
case 'p':
prompt = EARGF(usage());
menu.prompt = EARGF(usage());
break;
case 'r':
menu.rows = strtol(EARGF(usage()), nil, 10);
break;
case 's':
screen_hint = strtol(EARGF(usage()), nil, 10);
@ -249,11 +248,13 @@ main(int argc, char *argv[]) {
srv.preselect = event_preselect;
ixp_listen(&srv, ConnectionNumber(display), nil, event_fdready, event_fdclosed);
ontop = !strcmp(readctl("bar on "), "top");
menu.ontop = !strcmp(readctl("/ctl", "bar "), "on top");
client_readconfig(&cnorm, &csel, &font);
itempad = (font->height & ~1) + font->pad.min.x + font->pad.max.x;
cmplbuf = Bfdopen(0, OREAD);
items = populate_list(cmplbuf, false);
match.all = populate_list(cmplbuf, false);
if(!isatty(cmplbuf->fid))
ixp_listen(&srv, cmplbuf->fid, inbuf, check_competions, nil);
@ -268,21 +269,18 @@ main(int argc, char *argv[]) {
parse_keys(buffer);
}
histidx = &hist;
histsel = &hist;
link(&hist, &hist);
if(histfile) {
inbuf = Bopen(histfile, OREAD);
if(inbuf) {
item = populate_list(inbuf, true);
if(item) {
link(item->prev, &hist);
link(&hist, item);
}
Bterm(inbuf);
if(histfile && (inbuf = Bopen(histfile, OREAD))) {
item = filter_list(populate_list(inbuf, true), "");
if(item->string) {
link(item->prev, &hist);
link(&hist, item);
}
Bterm(inbuf);
}
if(barwin == nil)
if(menu.win == nil)
menu_init();
init_screens();

View File

@ -4,270 +4,220 @@
#include <unistd.h>
#include "fns.h"
static Handlers handlers;
static int ltwidth;
static void _menu_draw(bool);
enum {
ACCEPT = CARET_LAST,
REJECT,
HIST,
KILL,
CMPL_NEXT,
CMPL_PREV,
CMPL_FIRST,
CMPL_LAST,
CMPL_NEXT_PAGE,
CMPL_PREV_PAGE,
};
static Handlers handlers;
static int promptw;
void
menu_init(void) {
WinAttr wa;
wa.event_mask = ExposureMask | KeyPressMask;
barwin = createwindow(&scr.root, Rect(-1, -1, 1, 1), scr.depth, InputOutput,
&wa, CWEventMask);
menu.win = createwindow(&scr.root, Rect(-1, -1, 1, 1), scr.depth, InputOutput,
&wa, CWEventMask);
if(scr.xim)
barwin->xic = XCreateIC(scr.xim,
XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, barwin->xid,
XNFocusWindow, barwin->xid,
nil);
menu.win->xic = XCreateIC(scr.xim,
XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, menu.win->xid,
XNFocusWindow, menu.win->xid,
nil);
changeprop_long(barwin, Net("WM_WINDOW_TYPE"), "ATOM",
(long[]){ TYPE("MENU") }, 1);
changeprop_string(barwin, "_WMII_TAGS", "sel");
changeprop_textlist(barwin, "WM_CLASS", "STRING",
(char*[3]){ "wimenu", "wimenu", nil });
changeprop_long(menu.win, Net("WM_WINDOW_TYPE"), "ATOM", (long[]){ TYPE("MENU") }, 1);
changeprop_string(menu.win, "_WMII_TAGS", "sel");
changeprop_textlist(menu.win, "WM_CLASS", "STRING", (char*[3]){ "wimenu", "wimenu" });
sethandler(barwin, &handlers);
mapwin(barwin);
sethandler(menu.win, &handlers);
mapwin(menu.win);
int i = 0;
while(!grabkeyboard(barwin)) {
while(!grabkeyboard(menu.win)) {
if(i++ > 1000)
fatal("can't grab keyboard");
usleep(1000);
}
}
static void
menu_unmap(long id, void *p) {
void
menu_show(void) {
Rectangle r;
USED(id, p);
unmapwin(barwin);
XFlush(display);
}
if(menu.prompt)
promptw = textwidth(font, menu.prompt) + itempad;
static void
selectitem(Item *i) {
if(i != matchidx) {
caret_set(input.filter_start, input.pos - input.string);
caret_insert(i->string, 0);
matchidx = i;
}
}
r = textextents_l(font, "<", 1, nil);
menu.arrow = Pt(Dy(r) + itempad/2, Dx(r) + itempad/2);
static void
menu_cmd(int op, int motion) {
int n;
menu.height = labelh(font);
switch(op) {
case HIST:
n = input.pos - input.string;
caret_insert(history_search(motion, input.string, n), true);
input.pos = input.string + n;
break;
case KILL:
caret_delete(BACKWARD, motion);
break;
default:
goto next;
}
update_filter(true);
next:
switch(op) {
case ACCEPT:
srv.running = false;
if(!matchidx && matchfirst->retstring && !motion)
if(input.filter_start == 0 && input.pos == input.end)
menu_cmd(CMPL_FIRST, 0);
if(!motion && matchidx && !strcmp(input.string, matchidx->string))
lprint(1, "%s", matchidx->retstring);
else
lprint(1, "%s", input.string);
break;
case REJECT:
srv.running = false;
result = 1;
break;
case BACKWARD:
case FORWARD:
caret_move(op, motion);
update_input();
break;
case CMPL_NEXT:
selectitem(matchidx ? matchidx->next : matchfirst);
break;
case CMPL_PREV:
selectitem((matchidx ? matchidx : matchstart)->prev);
break;
case CMPL_FIRST:
matchstart = matchfirst;
matchend = nil;
selectitem(matchstart);
break;
case CMPL_LAST:
selectitem(matchfirst->prev);
break;
case CMPL_NEXT_PAGE:
if(matchend)
selectitem(matchend->next);
break;
case CMPL_PREV_PAGE:
matchend = matchstart->prev;
matchidx = nil;
_menu_draw(false);
selectitem(matchstart);
break;
}
freeimage(menu.buf);
menu.buf = allocimage(Dx(scr.rect),
!!menu.rows * 2 * menu.arrow.y + (menu.rows + 1) * menu.height,
menu.win->depth);
mapwin(menu.win);
raisewin(menu.win);
menu_draw();
}
/* I'd prefer to use ⌃ and ⌄, but few fonts support them. */
static void
_menu_draw(bool draw) {
Rectangle r, rd, rp, r2, extent;
CTuple *c;
Item *i;
int inputw, itemoff, end, pad, n, offset;
drawarrow(Image *img, Rectangle r, int up, Color *col) {
Point p[3], pt;
r = barwin->r;
r = rectsetorigin(r, ZP);
pt = Pt(menu.arrow.x - itempad/2, menu.arrow.y - itempad/2 & ~1);
pad = (font->height & ~1) + font->pad.min.x + font->pad.max.x;
p[1] = Pt(r.min.x + Dx(r)/2, up ? r.min.y + itempad/4 : r.max.y - itempad/4);
p[0] = Pt(p[1].x - pt.x/2, up ? p[1].y + pt.y : p[1].y - pt.y);
p[2] = Pt(p[1].x + pt.x/2, p[0].y);
drawpoly(img, p, nelem(p), CapProjecting, 1, col);
}
rd = r;
rp = ZR; // SET(rp)
if (prompt) {
if (!promptw)
promptw = textwidth(font, prompt) + 2 * ltwidth + pad;
rd.min.x += promptw;
static Rectangle
slice(Rectangle *rp, int x, int y) {
Rectangle r;
rp = r;
rp.max.x = promptw;
}
r = *rp;
if(x)
rp->min.x += x, r.max.x = min(rp->min.x, rp->max.x);
if(y)
rp->min.y += y, r.max.y = min(rp->min.y, rp->max.y);
return r;
}
inputw = min(Dx(rd) / 3, maxwidth);
inputw = max(inputw, textwidth(font, input.string)) + pad;
itemoff = inputw + 2 * ltwidth;
end = Dx(rd) - ltwidth;
static bool
nextrect(Item *i, Rectangle *rp, Rectangle *src) {
Rectangle r;
fill(ibuf, r, &cnorm.bg);
if(matchend && matchidx == matchend->next)
matchstart = matchidx;
else if(matchidx == matchstart->prev)
matchend = matchidx;
if (matchend == nil)
matchend = matchstart;
if(matchend == matchstart->prev && matchstart != matchidx) {
n = itemoff;
matchstart = matchend;
for(i=matchend; ; i=i->prev) {
n += i->width + pad;
if(n > end)
break;
matchstart = i;
if(i == matchfirst)
break;
}
}
if(!draw)
return;
r2 = rd;
for(i=matchstart; i->string; i=i->next) {
r2.min.x = promptw + itemoff;
itemoff = itemoff + i->width + pad;
r2.max.x = promptw + min(itemoff, end);
if(i != matchstart && itemoff > end)
break;
c = (i == matchidx) ? &csel : &cnorm;
fill(ibuf, r2, &c->bg);
drawstring(ibuf, font, r2, Center, i->string, &c->fg);
matchend = i;
if(i->next == matchfirst)
break;
}
r2 = rd;
r2.min.x = promptw + inputw;
if(matchstart != matchfirst)
drawstring(ibuf, font, r2, West, "<", &cnorm.fg);
if(matchend->next != matchfirst)
drawstring(ibuf, font, r2, East, ">", &cnorm.fg);
r2 = rd;
r2.max.x = promptw + inputw;
drawstring(ibuf, font, r2, West, input.string, &cnorm.fg);
extent = textextents_l(font, input.string, input.pos - input.string, &offset);
r2.min.x = promptw + offset + font->pad.min.x - extent.min.x + pad/2 - 1;
r2.max.x = r2.min.x + 2;
r2.min.y++;
r2.max.y--;
border(ibuf, r2, 1, &cnorm.border);
if (prompt)
drawstring(ibuf, font, rp, West, prompt, &cnorm.fg);
border(ibuf, rd, 1, &cnorm.border);
copyimage(barwin, r, ibuf, ZP);
if(menu.rows)
r = slice(src, 0, menu.height);
else
r = slice(src, i->width, 0);
return (Dx(*src) >= 0 && Dy(*src) >= 0) && (*rp = r, 1);
}
void
menu_draw(void) {
_menu_draw(true);
Rectangle barr, extent, itemr, inputr, r, r2;
Item *item;
int inputw, offset;
barr = r2 = Rect(0, 0, Dx(menu.win->r), menu.height);
inputw = max(match.maxwidth + textwidth_l(font, input.string, min(input.filter_start, strlen(input.string))),
max(itempad + textwidth(font, input.string),
Dx(barr) / 3));
/* Calculate items box, w/ and w/o arrows */
if(menu.rows) {
menu.itemr = barr;
menu.itemr.max.y += Dy(barr) * (menu.rows - 1);
if(menu.ontop)
menu.itemr = rectaddpt(menu.itemr, Pt(0, Dy(barr)));
itemr = menu.itemr;
if(match.start != match.first)
menu.itemr = rectaddpt(menu.itemr, Pt(0, menu.arrow.y));
}
else {
itemr = r2;
slice(&itemr, inputw + promptw, 0);
menu.itemr = Rect(itemr.min.x + menu.arrow.x, itemr.min.y,
itemr.max.x - menu.arrow.x, itemr.max.y);
}
fill(menu.buf, menu.buf->r, &cnorm.bg);
/* Draw items */
item = match.start, r2 = menu.itemr;
nextrect(item, &r, &r2);
do {
match.end = item;
if(item->string)
fillstring(menu.buf, font, r, West, item->string,
(item == match.sel ? &csel : &cnorm), 0);
item = item->next;
} while(item != match.first && nextrect(item, &r, &r2));
/* Adjust dimensions for arrows/number of items */
if(menu.rows)
itemr.max.y = r.max.y + (match.end->next != match.first ? menu.arrow.y : 0);
else
itemr.max.x = r.max.x + menu.arrow.x;
if(menu.rows && !menu.ontop)
barr = rectaddpt(barr, Pt(0, itemr.max.y));
/* Draw indicators */
if(!menu.rows && match.start != match.first)
drawstring(menu.buf, font, itemr, West, "<", &cnorm.fg);
if(!menu.rows && match.end->next != match.first)
drawstring(menu.buf, font, itemr, East, ">", &cnorm.fg);
if(menu.rows && match.start != match.first)
drawarrow(menu.buf, itemr, 1, &cnorm.fg);
if(menu.rows && match.end->next != match.first)
drawarrow(menu.buf, itemr, 0, &cnorm.fg);
/* Draw prompt */
r2 = barr;
if(menu.prompt)
drawstring(menu.buf, font, slice(&r2, promptw, 0),
West, menu.prompt, &cnorm.fg);
/* Border input/horizontal items */
border(menu.buf, r2, 1, &cnorm.border);
/* Draw input */
inputr = slice(&r2, inputw, 0);
drawstring(menu.buf, font, inputr, West, input.string, &cnorm.fg);
/* Draw cursor */
extent = textextents_l(font, input.string, input.pos - input.string, &offset);
r2 = insetrect(inputr, 2);
r2.min.x = inputr.min.x - extent.min.x + offset + font->pad.min.x + itempad/2 - 1;
r2.max.x = r2.min.x + 1;
fill(menu.buf, r2, &cnorm.border);
/* Reshape window */
r = scr.rect;
if(menu.ontop)
r.max.y = r.min.y + itemr.max.y;
else
r.min.y = r.max.y - barr.max.y;
reshapewin(menu.win, r);
/* Border window */
r = rectsubpt(r, r.min);
border(menu.buf, r, 1, &cnorm.border);
copyimage(menu.win, r, menu.buf, ZP);
}
void
menu_show(void) {
Rectangle r;
int height, pad;
static Item*
pagestart(Item *i) {
Rectangle r, r2;
USED(menu_unmap);
r = menu.itemr;
nextrect(i, &r2, &r);
while(i->prev != match.first->prev && nextrect(i->prev, &r2, &r))
i = i->prev;
return i;
}
ltwidth = textwidth(font, "<");
pad = (font->height & ~1)/2;
height = labelh(font);
r = scr.rect;
if(ontop)
r.max.y = r.min.y + height;
else
r.min.y = r.max.y - height;
reshapewin(barwin, r);
freeimage(ibuf);
ibuf = allocimage(Dx(r), Dy(r), scr.depth);
mapwin(barwin);
raisewin(barwin);
menu_draw();
static void
selectitem(Item *i) {
if(i != match.sel) {
caret_set(input.filter_start, input.pos - input.string);
caret_insert(i->string, 0);
match.sel = i;
if(i == match.start->prev)
match.start = pagestart(i);
if(i == match.end->next)
match.start = i;
}
}
static bool
kdown_event(Window *w, void *aux, XKeyEvent *e) {
char **action, **p;
char *key;
char buf[32];
char buf[128];
int num, status;
KeySym ksym;
@ -276,8 +226,7 @@ kdown_event(Window *w, void *aux, XKeyEvent *e) {
status = XLookupBoth;
if(w->xic)
num = Xutf8LookupString(w->xic, e, buf, sizeof buf - 1, &ksym,
&status);
num = Xutf8LookupString(w->xic, e, buf, sizeof buf - 1, &ksym, &status);
else
num = XLookupString(e, buf, sizeof buf - 1, &ksym, nil);
@ -319,37 +268,65 @@ kdown_event(Window *w, void *aux, XKeyEvent *e) {
have(LWORD) ? WORD :
have(LLINE) ? LINE :
-1);
switch(getsym(action[0])) {
case LACCEPT:
menu_cmd(ACCEPT, have(LLITERAL));
break;
case LBACKWARD:
menu_cmd(BACKWARD, amount);
break;
case LCOMPLETE:
amount = (
have(LNEXT) ? CMPL_NEXT :
have(LPREV) ? CMPL_PREV :
have(LNEXTPAGE) ? CMPL_NEXT_PAGE :
have(LPREVPAGE) ? CMPL_PREV_PAGE :
have(LFIRST) ? CMPL_FIRST :
have(LLAST) ? CMPL_LAST :
CMPL_NEXT);
menu_cmd(amount, 0);
break;
case LFORWARD:
menu_cmd(FORWARD, amount);
break;
default:
return false;
case LHISTORY:
menu_cmd(HIST, have(LBACKWARD) ? BACKWARD : FORWARD);
num = input.pos - input.string;
amount = have(LBACKWARD) ? BACKWARD : FORWARD;
caret_insert(history_search(amount, input.string, num), true);
input.pos = input.string + num;
update_filter(true);
break;
case LKILL:
menu_cmd(KILL, amount);
caret_delete(BACKWARD, amount);
update_filter(true);
break;
case LACCEPT:
srv.running = false;
if(!have(LLITERAL) && !match.sel && match.start->retstring)
if(input.filter_start == 0 && input.pos == input.end)
selectitem(match.start);
if(!have(LLITERAL) && match.sel && !strcmp(input.string, match.sel->string))
lprint(1, "%s", match.sel->retstring);
else
lprint(1, "%s", input.string);
break;
case LBACKWARD:
caret_move(BACKWARD, amount);
update_input();
break;
case LCOMPLETE:
if(have(LNEXT))
selectitem(match.sel ? match.sel->next : match.first);
else if(have(LPREV))
selectitem((match.sel ? match.sel : match.start)->prev);
else if(have(LFIRST)) {
match.start = match.first;
selectitem(match.start);
}
else if(have(LLAST))
selectitem(match.first->prev);
else if(have(LNEXTPAGE))
selectitem(match.end->next);
else if(have(LPREVPAGE)) {
match.start = pagestart(match.start->prev);
selectitem(match.start);
}
break;
case LFORWARD:
caret_move(FORWARD, amount);
update_input();
break;
case LREJECT:
menu_cmd(REJECT, 0);
srv.running = false;
result = 1;
break;
}
menu_draw();
}
return false;
}

View File

@ -191,7 +191,7 @@ main(int argc, char *argv[]) {
client_init(nil);
if(tray.edge == 0)
tray.edge = West | (!strcmp(readctl("bar on "), "top") ? North : South);
tray.edge = West | (!strcmp(readctl("/ctl", "bar on "), "top") ? North : South);
client_readconfig(&tray.normcolors, &tray.selcolors, &tray.font);

View File

@ -195,9 +195,7 @@ bar_draw(WMScreen *s) {
align = Center;
if(b == s->bar[BRight])
align = East;
fill(ibuf, b->r, &b->colors.bg);
drawstring(ibuf, def.font, b->r, align, b->text, &b->colors.fg);
border(ibuf, b->r, 1, &b->colors.border);
fillstring(ibuf, def.font, b->r, align, b->text, &b->colors, 1);
}
if(s->barwin_rgba != (s->barwin->depth == 32))

View File

@ -220,7 +220,8 @@ apply_rules(Client *c) {
bool ret, more;
ret = true;
for(r=def.rules.rule; r; r=r->next)
more = true;
for(r=def.rules.rule; r && more; r=r->next)
if(regexec(r->regex, c->props, nil, 0)) {
more = false;
for(rv=r->values; rv; rv=rv->next) {
@ -234,15 +235,15 @@ apply_rules(Client *c) {
}else {
bufclear();
bufprint("%s %s", rv->key, rv->value);
m = ixp_message(buffer, sizeof buffer, MsgPack);
if(!waserror()) {
m = ixp_message(buffer, _buf_end - buffer, MsgPack);
if(waserror())
warning("processing rule %q=%q: %r", rv->key, rv->value);
else {
message_client(c, &m);
poperror();
}
}
}
if(!more)
return ret;
}
return ret;
}
@ -1093,6 +1094,11 @@ client_extratags(Client *c) {
toks[i] = nil;
tags = comm(CLeft, toks, c->retags);
if(i == 1 && !c->tagre.regex && !c->tagvre.regex) {
free(tags);
return nil;
}
fmtstrinit(&fmt);
if(i > 1)
join(tags, "+", &fmt);
@ -1131,17 +1137,16 @@ client_applytags(Client *c, const char *tags) {
/* Check for regex. */
if(cur[0] == '/') {
cur++;
*strchr(cur, '/') = '\0';
*strrchr(cur, '/') = '\0';
if(add == '+')
reinit(&c->tagre, cur);
else if(add == '-')
reinit(&c->tagvre, cur);
}
trim(cur, " \t\r\n");
if(!strcmp(cur, "~"))
else if(!strcmp(cur, "~"))
c->floating = add ? On : Never;
else {
trim(cur, " \t\r\n");
if(!strcmp(cur, "sel"))
cur = selview->name;
else if(Mbsearch(cur, badtags, bsstrcmp))

View File

@ -313,8 +313,7 @@ EXTERN struct Defs {
uint keyssz;
Ruleset colrules;
Ruleset rules;
char grabmod[5];
ulong mod;
long mod;
uint border;
uint snap;
int colmode;

View File

@ -398,6 +398,7 @@ pushlabel(Image *img, Rectangle *rp, char *s, CTuple *col) {
w = min(w, Dx(*rp) - 30); /* Magic number. */
if(w > 0) {
r = *rp;
r.min.x = r.max.x - w;
rp->max.x -= w;
if(0)
drawline(img, Pt(rp->max.x, r.min.y+2),
@ -406,6 +407,7 @@ pushlabel(Image *img, Rectangle *rp, char *s, CTuple *col) {
drawstring(img, def.font, r, East,
s, &col->fg);
}
free(s);
}
void
@ -415,7 +417,6 @@ frame_draw(Frame *f) {
CTuple *col;
Image *img;
char *s;
uint w;
int n, m;
if(f == nil || f->view != selview || f->area == nil)
@ -443,6 +444,9 @@ frame_draw(Frame *f) {
f->titlebar = insetrect(r, 3);
f->titlebar.max.y += 3;
f->grabbox = insetrect(r, 2);
f->grabbox.max.x = f->grabbox.min.x + Dy(f->grabbox);
/* Odd focus. Unselected, with keyboard focus. */
/* Draw a border just inside the titlebar. */
if(c != selclient() && c == disp.focus) {
@ -450,15 +454,9 @@ frame_draw(Frame *f) {
border(img, insetrect(r, 2), 1, &def.focuscolor.border);
}
/* grabbox */
r.min = Pt(2, 2);
r.max.y -= 2;
r.max.x = r.min.x + Dy(r);
f->grabbox = r;
if(c->urgent)
fill(img, r, &col->fg);
border(img, r, 1, &col->border);
fill(img, f->grabbox, &col->fg);
border(img, f->grabbox, 1, &col->border);
/* Odd focus. Selected, without keyboard focus. */
/* Draw a border around the grabbox. */
@ -466,38 +464,34 @@ frame_draw(Frame *f) {
border(img, insetrect(r, -1), 1, &def.normcolor.bg);
/* Draw a border on borderless+titleless selected apps. */
if(f->area->floating && c->borderless && c->titleless && !c->fullscreen && c == selclient())
if(c->borderless && c->titleless && f->area->floating && !c->fullscreen && c == selclient())
setborder(c->framewin, def.border, &def.focuscolor.border);
else
setborder(c->framewin, 0, &def.focuscolor.border);
/* Label */
r.min.x = r.max.x;
r.max.x = fr.max.x;
r.min.y = 0;
r.max.y = labelh(def.font);
r = Rect(f->grabbox.max.x, 0, fr.max.x, labelh(def.font));
/* Draw count on frames in 'max' columns. */
if(f->area->max && !resizing) {
/* XXX */
n = stack_count(f, &m);
s = smprint("%d/%d", m, n);
pushlabel(img, &r, s, col);
free(s);
pushlabel(img, &r, smprint("%d/%d", m, n), col);
}
/* Label clients with extra tags. */
if((s = client_extratags(c))) {
if((s = client_extratags(c)))
pushlabel(img, &r, s, col);
free(s);
}else if(f->area->floating) /* Make sure floating clients have room for their indicators. */
r.max.x -= Dx(f->grabbox);
if(f->area->floating) /* Make sure floating clients have room for their indicators. */
r.max.x -= f->grabbox.max.x;
if(!ewmh_responsive_p(c))
r.min.x += drawstring(img, def.font, r, West, "(wedged) ", &col->fg);
w = drawstring(img, def.font, r, West, c->name, &col->fg);
r.min.x += drawstring(img, def.font, r, West, c->name, &col->fg);
/* Draw inner border on floating clients. */
if(f->area->floating) {
r.min.x = r.min.x + w + 10;
r.min.x += 10;
r.max.x += Dx(f->grabbox);
r.min.y = f->grabbox.min.y;
r.max.y = f->grabbox.max.y;

View File

@ -372,8 +372,7 @@ main(int argc, char *argv[]) {
initdisplay();
traperrors(true);
selectinput(&scr.root, EnterWindowMask
| SubstructureRedirectMask);
selectinput(&scr.root, SubstructureRedirectMask);
if(traperrors(false))
fatal("another window manager is already running");
@ -388,7 +387,7 @@ main(int argc, char *argv[]) {
sock = ixp_announce(address);
if(sock < 0)
fatal("Can't create socket '%s': %r", address);
fatal("Can't create socket %q: %r", address);
closeexec(ConnectionNumber(display));
closeexec(sock);
@ -413,7 +412,6 @@ main(int argc, char *argv[]) {
def.incmode = ISqueeze;
def.mod = Mod1Mask;
strcpy(def.grabmod, "Mod1");
loadcolor(&def.focuscolor, FOCUSCOLORS, nil);
loadcolor(&def.normcolor, NORMCOLORS, nil);

View File

@ -656,7 +656,6 @@ message_root(void *p, IxpMsg *m) {
if(!parsekey(s, &i, nil) || i == 0)
return Ebadvalue;
utflcpy(def.grabmod, s, sizeof def.grabmod);
def.mod = i;
break;
case LINCMODE:
@ -700,7 +699,7 @@ readctl_root(void) {
bufprint("font %s\n", def.font->name);
bufprint("fontpad %d %d %d %d\n", def.font->pad.min.x, def.font->pad.max.x,
def.font->pad.max.y, def.font->pad.min.y);
bufprint("grabmod %s\n", def.grabmod);
bufprint("grabmod %s\n", (Mask){&def.mod, modkey_names});
bufprint("incmode %s\n", incmodetab[def.incmode]);
bufprint("normcolors %s\n", def.normcolor.colstr);
bufprint("view %s\n", selview->name);

View File

@ -426,7 +426,7 @@ xnamespace(int argc, char *argv[]) {
path = ixp_namespace();
if(path == nil)
fatal("can't find namespace: %r\n");
Blprint(outbuf, "%s\n", path);
Blprint(outbuf, "%s", path);
return 0;
}

View File

@ -58,15 +58,8 @@ static Font* font;
static int wborder;
char buffer[8092];
char* _buffer;
/* for XSetWMProperties to use */
int g_argc;
char **g_argv;
char *initial = "";
int cur;
static char* initial = "";
static int cur;
static char** labels; /* list of labels and commands */
static char** commands;
@ -78,13 +71,7 @@ void create_window(void);
void size_window(int, int);
void redraw(int, int);
void warpmouse(int, int);
void memory(void);
int args(void);
Cursor cursor[1];
Visual* render_visual;
void init_screens(void);
void
init_screens(void) {
Rectangle *rects;
@ -111,9 +98,6 @@ main(int argc, char **argv)
char *cp;
int i;
g_argc = argc;
g_argv = argv;
ARGBEGIN{
case 'v':
lprint(1, "%s\n", version);
@ -137,29 +121,24 @@ main(int argc, char **argv)
create_window();
numitems = argc;
labels = emalloc(numitems * sizeof *labels);
commands = emalloc(numitems * sizeof *labels);
for(i = 0; i < numitems; i++) {
labels[i] = argv[i];
commands[i] = argv[i];
if((cp = strchr(labels[i], ':')) != nil) {
*cp++ = '\0';
commands[i] = cp;
} else
commands[i] = labels[i];
}
if(strcmp(labels[i], initial) == 0)
cur = i;
}
client_init(address);
wborder = strtol(readctl("border "), nil, 10);
loadcolor(&cnorm, readctl("normcolors "), nil);
loadcolor(&csel, readctl("focuscolors "), nil);
font = loadfont(readctl("font "));
if(!font)
fatal("Can't load font");
wborder = strtol(readctl("/ctl", "border "), nil, 10);
client_readconfig(&cnorm, &csel, &font);
run_menu();
@ -167,28 +146,22 @@ main(int argc, char **argv)
return 0;
}
/* usage --- print a usage message and die */
void
usage(void)
{
lprint(2, "usage: %s -v\n", argv0);
lprint(2, " %s [-a <address>] [-i <arg>] menitem[:command] ...\n", argv0);
lprint(2, "usage: %s [-a <address>] [-i <arg>] <menitem>[:<command>] ...\n", argv0);
lprint(2, " %s -v\n", argv0);
exit(0);
}
/* run_menu --- put up the window, execute selected commands */
enum {
MouseMask =
ButtonPressMask
| ButtonReleaseMask
| ButtonMotionMask
| PointerMotionMask,
MenuMask =
MouseMask
| StructureNotifyMask
| ExposureMask
MouseMask = ButtonPressMask
| ButtonReleaseMask
| ButtonMotionMask
| PointerMotionMask,
MenuMask = MouseMask
| StructureNotifyMask
| ExposureMask
};
void
@ -197,8 +170,8 @@ run_menu(void)
XEvent ev;
int i, old, wide, high;
wide = 0;
high = labelh(font);
wide = 0;
for(i = 0; i < numitems; i++)
wide = max(wide, textwidth(font, labels[i]));
wide += font->height & ~1;
@ -231,12 +204,10 @@ run_menu(void)
break;
redraw(high, wide);
break;
case MapNotify:
redraw(high, wide);
break;
case Expose:
redraw(high, wide);
break;
case MapNotify:
case ConfigureNotify:
case MappingNotify:
break;
@ -244,13 +215,10 @@ run_menu(void)
}
}
/* set_wm_hints --- set all the window manager hints */
void
create_window(void)
{
WinAttr wa = { 0 };
XEvent e;
wa.override_redirect = true;
menuwin = createwindow(&scr.root, Rect(-1, -1, 0, 0),
@ -258,10 +226,8 @@ create_window(void)
&wa, CWOverrideRedirect);
selectinput(menuwin, MenuMask);
mapwin(menuwin);
XMaskEvent(display, StructureNotifyMask, &e);
if(!grabpointer(menuwin, nil, 0, MouseMask))
fatal("Failed to grab the mouse\n");
XSetCommand(display, menuwin->xid, g_argv, g_argc);
}
void
@ -284,34 +250,22 @@ size_window(int wide, int high)
p.y = min(p.y, scr.rect.max.y - h);
reshapewin(menuwin, rectaddpt(r, p));
//XSetWindowBackground(display, menuwin->xid, cnorm.bg);
setborder(menuwin, 1, &cnorm.border);
}
/* redraw --- actually redraw the menu */
void
redraw(int high, int wide)
{
Rectangle r;
CTuple *c;
int i;
r = Rect(0, 0, wide, high);
for(i = 0; i < numitems; i++) {
if(cur == i)
c = &csel;
else
c = &cnorm;
r = rectsetorigin(r, Pt(0, i * high));
fill(menuwin, r, &c->bg);
drawstring(menuwin, font, r, Center, labels[i], &c->fg);
fillstring(menuwin, font, r, Center, labels[i], (cur == i ? &csel : &cnorm), 0);
}
}
/* warpmouse --- bring the mouse to the menu */
void
warpmouse(int wide, int high)
{

View File

@ -2,37 +2,22 @@ MKSHELL=rc
path=$PLAN9/bin $path
eps = wmii.eps
calc = rc -c 'hoc -e $"*'
calc = rc -c 'echo 4k $* p | dc}
epsbox = `{sed -n '/^%%BoundingBox:/{s/.*://p; q;}' $eps}
iconwidth = 154
iconscale = `{*=$epsbox; $calc $iconwidth / '('$3 - $1')'}
iconheight = `{*=$epsbox; $calc '('$4 - $2') *' $iconscale}
%.png: %.eps
* = `{hoc -e'-('$epsbox')'}
x = $1
y = $2
gs -q -dBATCH -dNOPAUSE -s'DEVICE=pngalpha' -s'OutputFile='$target -g$iconwidth'x'$iconheight - <<!
$iconscale $iconscale scale
$x $y translate
($eps) run
showpage
quit
!
optipng -fix $target
iconwidth = 16
imagewidth = 154
%.pdf: %.eps
sh epstopdf $stem.eps
%-small.png: %.eps
iconwidth = 16
iconscale = `{*=$epsbox; hoc -e $iconwidth/'('$3-' '$1')'}
iconheight = `{*=$epsbox; hoc -e '('$4-' '$2')*'$iconscale}
epsbox = `{sed -n '/^%%BoundingBox:/{s/.*://p; q;}' $stem.eps}
iconscale = `{*=$epsbox; $calc $iconwidth $3 $1 -/}
iconheight = `{*=$epsbox; $calc $4 $2 - $iconscale '*'}
* = `{hoc -e'-('$epsbox')'}
x = $1
y = $2
gs -q -dBATCH -dNOPAUSE -s'DEVICE=pngalpha' -s'OutputFile='$target -g$iconwidth'x'$iconheight - <<!
gs -q -dBATCH -dNOPAUSE -s'DEVICE=pngalpha' -s'OutputFile='$target -g$iconwidth^x^$iconheight - <<!
$iconscale $iconscale scale
$x $y translate
($eps) run
@ -41,3 +26,19 @@ iconheight = `{*=$epsbox; $calc '('$4 - $2') *' $iconscale}
!
optipng -fix $target
%.png: %.eps
epsbox = `{sed -n '/^%%BoundingBox:/{s/.*://p; q;}' $stem.eps}
imagescale = `{*=$epsbox; $calc $imagewidth $3 $1 -/}
imageheight = `{*=$epsbox; $calc $4 $2 - $imagescale '*'}
* = `{hoc -e'-('$epsbox')'}
x = $1
y = $2
gs -q -dBATCH -dNOPAUSE -s'DEVICE=pngalpha' -s'OutputFile='$target -g$imagewidth^x^$imageheight - <<!
$imagescale $imagescale scale
$x $y translate
($eps) run
showpage
quit
!
optipng -fix $target

View File

@ -6,7 +6,7 @@
# define CLIENTEXTERN extern
#endif
char* readctl(char*);
char* readctl(char*, char*);
void client_init(char*);
CLIENTEXTERN IxpClient* client;

View File

@ -30,8 +30,8 @@ typedef enum Align Align;
#define Dx(r) ((r).max.x - (r).min.x)
#define Dy(r) ((r).max.y - (r).min.y)
#define Pt(x, y) ((Point){(x), (y)})
#define Rpt(p, q) ((Rectangle){p, q})
#define Rect(x0, y0, x1, y1) ((Rectangle){Pt(x0, y0), Pt(x1, y1)})
#define Rpt(p, q) ((Rectangle){(p), (q)})
#define Rect(x0, y0, x1, y1) Rpt(Pt(x0, y0), Pt(x1, y1))
Point addpt(Point, Point);
Point divpt(Point, Point);

View File

@ -42,13 +42,10 @@ enum {
int Blprint(Biobuf*, const char*, ...);
int Bvlprint(Biobuf*, const char*, va_list);
extern char* _buffer;
void _die(char*, int, char*, ...);
void backtrace(char*);
extern char buffer[8092];
void closeexec(int);
char** comm(int, char**, char**);
extern char* const _buf_end;
int doublefork(void);
void* emalloc(uint);
void* emallocz(uint);
@ -90,6 +87,10 @@ int unquote(char*, char*[], int);
int utflcpy(char*, const char*, int);
int vlprint(int, const char*, va_list);
char* vsxprint(const char*, va_list);
extern char* _buffer;
extern char buffer[8092];
extern char* const _buf_end;
#define bufclear() \
BLOCK( _buffer = buffer; _buffer[0] = '\0' )
#define bufprint(...) \

View File

@ -261,6 +261,7 @@ void drawpoly(Image*, Point*, int, int cap, int w, Color*);
uint drawstring(Image*, Font*, Rectangle, Align, const char*, Color*);
void fill(Image*, Rectangle, Color*);
void fillpoly(Image*, Point*, int, Color*);
uint fillstring(Image*, Font*, Rectangle, Align, const char*, CTuple*, int border);
Window* findwin(XWindow);
void freefont(Font*);
void freeimage(Image *);

View File

@ -11,13 +11,13 @@ void
client_readconfig(CTuple *norm, CTuple *focus, Font **font) {
if(norm)
loadcolor(norm, readctl("normcolors "), nil);
loadcolor(norm, readctl("/ctl", "normcolors "), nil);
if(focus)
loadcolor(focus, readctl("focuscolors "), nil);
*font = loadfont(readctl("font "));
loadcolor(focus, readctl("/ctl", "focuscolors "), nil);
*font = loadfont(readctl("/ctl", "font "));
if(!*font)
fatal("Can't load font %q", readctl("font "));
sscanf(readctl("fontpad "), "%d %d %d %d",
fatal("Can't load font %q", readctl("/ctl", "font "));
sscanf(readctl("/ctl", "fontpad "), "%d %d %d %d",
&(*font)->pad.min.x, &(*font)->pad.max.x,
&(*font)->pad.min.x, &(*font)->pad.max.y);
}

View File

@ -10,20 +10,21 @@
#include <stuff/clientutil.h>
#include <stuff/util.h>
static IxpCFid* ctlfid;
static char ctl[1024];
static char* ectl;
char*
readctl(char *key) {
readctl(char *ctlname, char *key) {
static char ctlfile[128];
static char ctl[1024];
static char* ectl;
IxpCFid *fid;
char *s, *p;
int nkey, n;
if(ctlfid == nil) {
ctlfid = ixp_open(client, "ctl", OREAD);
n = ixp_read(ctlfid, ctl, 1023);
if(strcmp(ctlname, ctlfile)) {
strncpy(ctlfile, ctlname, sizeof ctlfile);
fid = ixp_open(client, ctlfile, OREAD);
n = ixp_read(fid, ctl, sizeof ctl - 1);
ectl = ctl + n;
ixp_close(ctlfid);
ixp_close(fid);
}
nkey = strlen(key);
@ -36,7 +37,7 @@ readctl(char *key) {
n = (s ? s : ectl) - p;
s = freelater(emalloc(n + 1));
s[n] = '\0';
return strncpy(s, p, n);
return memcpy(s, p, n);
}
} while((p = strchr(p, '\n')));
return "";

View File

@ -4,6 +4,17 @@
#include <string.h>
#include "../x11.h"
uint
fillstring(Image *dst, Font *font,
Rectangle r, Align align,
const char *text, CTuple *col, int borderw) {
fill(dst, r, &col->bg);
if(borderw)
border(dst, r, borderw, &col->border);
return drawstring(dst, font, r, align, text, &col->fg);
}
uint
drawstring(Image *dst, Font *font,
Rectangle r, Align align,

View File

@ -41,8 +41,8 @@ tags:
for f in $(OBJ); do \
[ -f "$$f.c" ] && files="$$files $$f.c"; \
done; \
echo CTAGS $$files $(TAGFILES) || \
ctags $$files $(TAGFILES)
echo CTAGS $$files $(TAGFILES); \
$(DEBUG) $(CTAGS) $$files $(TAGFILES)
.PHONY: all options clean dist install uninstall depend cleandep tags
.PHONY: simpleuninstall simpleinstall

View File

@ -49,7 +49,7 @@ undup() { # GCC is crap.
nl=0
maxl=6
}
/: (error|note): .?Each undeclared identifier|: error: for each function it appears|is dangerous, better use|is almost always misused|: In function |: At top level:|support .long long.|use of C99 long long|ISO C forbids conversion|warning:.*warn_unused_result/ {
tolower($0) ~ /: (error|note): .?each undeclared identifier|: error: for each function it appears|is dangerous, better use|is almost always misused|: in function |: at top level:|support .long long.|use of c99 long long|iso c forbids conversion|warning:.*warn_unused_result/ {
next
}
$1 == "warning:" {