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

View File

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

View File

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

View File

@ -11,8 +11,6 @@
#include <stuff/x.h> #include <stuff/x.h>
#include <stuff/util.h> #include <stuff/util.h>
#define BLOCK(x) do { x; }while(0)
#ifndef EXTERN #ifndef EXTERN
# define EXTERN extern # define EXTERN extern
#endif #endif
@ -69,38 +67,40 @@ EXTERN struct {
int filter_start; int filter_start;
} input; } 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 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 IxpServer srv;
EXTERN Window* barwin; EXTERN struct {
Item* all;
Item* first;
Item* start;
Item* end;
Item* sel;
int maxwidth;
} match;
EXTERN Item* items; Font* font;
EXTERN Item* matchfirst; CTuple cnorm;
EXTERN Item* matchstart; CTuple csel;
EXTERN Item* matchend;
EXTERN Item* matchidx;
EXTERN Item hist; EXTERN Item hist;
EXTERN Item* histidx; EXTERN Item* histsel;
EXTERN int maxwidth; EXTERN int itempad;
EXTERN int result; EXTERN int result;
EXTERN char* (*find)(const char*, const char*); EXTERN char* (*find)(const char*, const char*);
EXTERN int (*compare)(const char*, const char*, size_t); EXTERN int (*compare)(const char*, const char*, size_t);
EXTERN char* prompt;
EXTERN int promptw;

View File

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

View File

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

View File

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

View File

@ -4,270 +4,220 @@
#include <unistd.h> #include <unistd.h>
#include "fns.h" #include "fns.h"
static Handlers handlers; static Handlers handlers;
static int promptw;
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,
};
void void
menu_init(void) { menu_init(void) {
WinAttr wa; WinAttr wa;
wa.event_mask = ExposureMask | KeyPressMask; wa.event_mask = ExposureMask | KeyPressMask;
barwin = createwindow(&scr.root, Rect(-1, -1, 1, 1), scr.depth, InputOutput, menu.win = createwindow(&scr.root, Rect(-1, -1, 1, 1), scr.depth, InputOutput,
&wa, CWEventMask); &wa, CWEventMask);
if(scr.xim) if(scr.xim)
barwin->xic = XCreateIC(scr.xim, menu.win->xic = XCreateIC(scr.xim,
XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, barwin->xid, XNClientWindow, menu.win->xid,
XNFocusWindow, barwin->xid, XNFocusWindow, menu.win->xid,
nil); nil);
changeprop_long(barwin, Net("WM_WINDOW_TYPE"), "ATOM", changeprop_long(menu.win, Net("WM_WINDOW_TYPE"), "ATOM", (long[]){ TYPE("MENU") }, 1);
(long[]){ TYPE("MENU") }, 1); changeprop_string(menu.win, "_WMII_TAGS", "sel");
changeprop_string(barwin, "_WMII_TAGS", "sel"); changeprop_textlist(menu.win, "WM_CLASS", "STRING", (char*[3]){ "wimenu", "wimenu" });
changeprop_textlist(barwin, "WM_CLASS", "STRING",
(char*[3]){ "wimenu", "wimenu", nil });
sethandler(barwin, &handlers); sethandler(menu.win, &handlers);
mapwin(barwin); mapwin(menu.win);
int i = 0; int i = 0;
while(!grabkeyboard(barwin)) { while(!grabkeyboard(menu.win)) {
if(i++ > 1000) if(i++ > 1000)
fatal("can't grab keyboard"); fatal("can't grab keyboard");
usleep(1000); usleep(1000);
} }
} }
static void void
menu_unmap(long id, void *p) { menu_show(void) {
Rectangle r;
USED(id, p); if(menu.prompt)
unmapwin(barwin); promptw = textwidth(font, menu.prompt) + itempad;
XFlush(display);
}
static void r = textextents_l(font, "<", 1, nil);
selectitem(Item *i) { menu.arrow = Pt(Dy(r) + itempad/2, Dx(r) + itempad/2);
if(i != matchidx) {
caret_set(input.filter_start, input.pos - input.string);
caret_insert(i->string, 0);
matchidx = i;
}
}
static void menu.height = labelh(font);
menu_cmd(int op, int motion) {
int n;
switch(op) { freeimage(menu.buf);
case HIST: menu.buf = allocimage(Dx(scr.rect),
n = input.pos - input.string; !!menu.rows * 2 * menu.arrow.y + (menu.rows + 1) * menu.height,
caret_insert(history_search(motion, input.string, n), true); menu.win->depth);
input.pos = input.string + n;
break; mapwin(menu.win);
case KILL: raisewin(menu.win);
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;
}
menu_draw(); menu_draw();
} }
/* I'd prefer to use ⌃ and ⌄, but few fonts support them. */
static void static void
_menu_draw(bool draw) { drawarrow(Image *img, Rectangle r, int up, Color *col) {
Rectangle r, rd, rp, r2, extent; Point p[3], pt;
CTuple *c;
Item *i;
int inputw, itemoff, end, pad, n, offset;
r = barwin->r; pt = Pt(menu.arrow.x - itempad/2, menu.arrow.y - itempad/2 & ~1);
r = rectsetorigin(r, ZP);
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; static Rectangle
rp = ZR; // SET(rp) slice(Rectangle *rp, int x, int y) {
if (prompt) { Rectangle r;
if (!promptw)
promptw = textwidth(font, prompt) + 2 * ltwidth + pad;
rd.min.x += promptw;
rp = r; r = *rp;
rp.max.x = promptw; 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); static bool
inputw = max(inputw, textwidth(font, input.string)) + pad; nextrect(Item *i, Rectangle *rp, Rectangle *src) {
itemoff = inputw + 2 * ltwidth; Rectangle r;
end = Dx(rd) - ltwidth;
fill(ibuf, r, &cnorm.bg); if(menu.rows)
r = slice(src, 0, menu.height);
if(matchend && matchidx == matchend->next) else
matchstart = matchidx; r = slice(src, i->width, 0);
else if(matchidx == matchstart->prev) return (Dx(*src) >= 0 && Dy(*src) >= 0) && (*rp = r, 1);
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);
} }
void void
menu_draw(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 static Item*
menu_show(void) { pagestart(Item *i) {
Rectangle r; Rectangle r, r2;
int height, pad;
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, "<"); static void
selectitem(Item *i) {
pad = (font->height & ~1)/2; if(i != match.sel) {
height = labelh(font); caret_set(input.filter_start, input.pos - input.string);
caret_insert(i->string, 0);
r = scr.rect; match.sel = i;
if(ontop) if(i == match.start->prev)
r.max.y = r.min.y + height; match.start = pagestart(i);
else if(i == match.end->next)
r.min.y = r.max.y - height; match.start = i;
reshapewin(barwin, r); }
freeimage(ibuf);
ibuf = allocimage(Dx(r), Dy(r), scr.depth);
mapwin(barwin);
raisewin(barwin);
menu_draw();
} }
static bool static bool
kdown_event(Window *w, void *aux, XKeyEvent *e) { kdown_event(Window *w, void *aux, XKeyEvent *e) {
char **action, **p; char **action, **p;
char *key; char *key;
char buf[32]; char buf[128];
int num, status; int num, status;
KeySym ksym; KeySym ksym;
@ -276,8 +226,7 @@ kdown_event(Window *w, void *aux, XKeyEvent *e) {
status = XLookupBoth; status = XLookupBoth;
if(w->xic) if(w->xic)
num = Xutf8LookupString(w->xic, e, buf, sizeof buf - 1, &ksym, num = Xutf8LookupString(w->xic, e, buf, sizeof buf - 1, &ksym, &status);
&status);
else else
num = XLookupString(e, buf, sizeof buf - 1, &ksym, nil); 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(LWORD) ? WORD :
have(LLINE) ? LINE : have(LLINE) ? LINE :
-1); -1);
switch(getsym(action[0])) { switch(getsym(action[0])) {
case LACCEPT: default:
menu_cmd(ACCEPT, have(LLITERAL)); return false;
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;
case LHISTORY: 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; break;
case LKILL: 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; break;
case LREJECT: case LREJECT:
menu_cmd(REJECT, 0); srv.running = false;
result = 1;
break; break;
} }
menu_draw();
} }
return false; return false;
} }

View File

@ -191,7 +191,7 @@ main(int argc, char *argv[]) {
client_init(nil); client_init(nil);
if(tray.edge == 0) 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); client_readconfig(&tray.normcolors, &tray.selcolors, &tray.font);

View File

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

View File

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

View File

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

View File

@ -372,8 +372,7 @@ main(int argc, char *argv[]) {
initdisplay(); initdisplay();
traperrors(true); traperrors(true);
selectinput(&scr.root, EnterWindowMask selectinput(&scr.root, SubstructureRedirectMask);
| SubstructureRedirectMask);
if(traperrors(false)) if(traperrors(false))
fatal("another window manager is already running"); fatal("another window manager is already running");
@ -388,7 +387,7 @@ main(int argc, char *argv[]) {
sock = ixp_announce(address); sock = ixp_announce(address);
if(sock < 0) if(sock < 0)
fatal("Can't create socket '%s': %r", address); fatal("Can't create socket %q: %r", address);
closeexec(ConnectionNumber(display)); closeexec(ConnectionNumber(display));
closeexec(sock); closeexec(sock);
@ -413,7 +412,6 @@ main(int argc, char *argv[]) {
def.incmode = ISqueeze; def.incmode = ISqueeze;
def.mod = Mod1Mask; def.mod = Mod1Mask;
strcpy(def.grabmod, "Mod1");
loadcolor(&def.focuscolor, FOCUSCOLORS, nil); loadcolor(&def.focuscolor, FOCUSCOLORS, nil);
loadcolor(&def.normcolor, NORMCOLORS, 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) if(!parsekey(s, &i, nil) || i == 0)
return Ebadvalue; return Ebadvalue;
utflcpy(def.grabmod, s, sizeof def.grabmod);
def.mod = i; def.mod = i;
break; break;
case LINCMODE: case LINCMODE:
@ -700,7 +699,7 @@ readctl_root(void) {
bufprint("font %s\n", def.font->name); bufprint("font %s\n", def.font->name);
bufprint("fontpad %d %d %d %d\n", def.font->pad.min.x, def.font->pad.max.x, 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); 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("incmode %s\n", incmodetab[def.incmode]);
bufprint("normcolors %s\n", def.normcolor.colstr); bufprint("normcolors %s\n", def.normcolor.colstr);
bufprint("view %s\n", selview->name); bufprint("view %s\n", selview->name);

View File

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

View File

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

View File

@ -2,37 +2,22 @@ MKSHELL=rc
path=$PLAN9/bin $path path=$PLAN9/bin $path
eps = wmii.eps eps = wmii.eps
calc = rc -c 'hoc -e $"*' calc = rc -c 'echo 4k $* p | dc}
epsbox = `{sed -n '/^%%BoundingBox:/{s/.*://p; q;}' $eps} iconwidth = 16
iconwidth = 154 imagewidth = 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
%.pdf: %.eps %.pdf: %.eps
sh epstopdf $stem.eps sh epstopdf $stem.eps
%-small.png: %.eps %-small.png: %.eps
iconwidth = 16 epsbox = `{sed -n '/^%%BoundingBox:/{s/.*://p; q;}' $stem.eps}
iconscale = `{*=$epsbox; hoc -e $iconwidth/'('$3-' '$1')'} iconscale = `{*=$epsbox; $calc $iconwidth $3 $1 -/}
iconheight = `{*=$epsbox; hoc -e '('$4-' '$2')*'$iconscale} iconheight = `{*=$epsbox; $calc $4 $2 - $iconscale '*'}
* = `{hoc -e'-('$epsbox')'} * = `{hoc -e'-('$epsbox')'}
x = $1 x = $1
y = $2 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 $iconscale $iconscale scale
$x $y translate $x $y translate
($eps) run ($eps) run
@ -41,3 +26,19 @@ iconheight = `{*=$epsbox; $calc '('$4 - $2') *' $iconscale}
! !
optipng -fix $target 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 # define CLIENTEXTERN extern
#endif #endif
char* readctl(char*); char* readctl(char*, char*);
void client_init(char*); void client_init(char*);
CLIENTEXTERN IxpClient* client; CLIENTEXTERN IxpClient* client;

View File

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

View File

@ -42,13 +42,10 @@ enum {
int Blprint(Biobuf*, const char*, ...); int Blprint(Biobuf*, const char*, ...);
int Bvlprint(Biobuf*, const char*, va_list); int Bvlprint(Biobuf*, const char*, va_list);
extern char* _buffer;
void _die(char*, int, char*, ...); void _die(char*, int, char*, ...);
void backtrace(char*); void backtrace(char*);
extern char buffer[8092];
void closeexec(int); void closeexec(int);
char** comm(int, char**, char**); char** comm(int, char**, char**);
extern char* const _buf_end;
int doublefork(void); int doublefork(void);
void* emalloc(uint); void* emalloc(uint);
void* emallocz(uint); void* emallocz(uint);
@ -90,6 +87,10 @@ int unquote(char*, char*[], int);
int utflcpy(char*, const char*, int); int utflcpy(char*, const char*, int);
int vlprint(int, const char*, va_list); int vlprint(int, const char*, va_list);
char* vsxprint(const char*, va_list); char* vsxprint(const char*, va_list);
extern char* _buffer;
extern char buffer[8092];
extern char* const _buf_end;
#define bufclear() \ #define bufclear() \
BLOCK( _buffer = buffer; _buffer[0] = '\0' ) BLOCK( _buffer = buffer; _buffer[0] = '\0' )
#define bufprint(...) \ #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*); uint drawstring(Image*, Font*, Rectangle, Align, const char*, Color*);
void fill(Image*, Rectangle, Color*); void fill(Image*, Rectangle, Color*);
void fillpoly(Image*, Point*, int, Color*); void fillpoly(Image*, Point*, int, Color*);
uint fillstring(Image*, Font*, Rectangle, Align, const char*, CTuple*, int border);
Window* findwin(XWindow); Window* findwin(XWindow);
void freefont(Font*); void freefont(Font*);
void freeimage(Image *); void freeimage(Image *);

View File

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

View File

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

View File

@ -4,6 +4,17 @@
#include <string.h> #include <string.h>
#include "../x11.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 uint
drawstring(Image *dst, Font *font, drawstring(Image *dst, Font *font,
Rectangle r, Align align, Rectangle r, Align align,

View File

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

View File

@ -49,7 +49,7 @@ undup() { # GCC is crap.
nl=0 nl=0
maxl=6 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 next
} }
$1 == "warning:" { $1 == "warning:" {