X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=st.c;h=b37069c6934e69b3007a350b7d77f8147002ab3a;hb=8f11e1cd034ff28ca47bb4955505db7fa8016ba8;hp=16bf68bf04804ab651140c71f24e6361bf81fd66;hpb=939e149544e4da958c333f3b6d00991d459c2e34;p=st.git diff --git a/st.c b/st.c index 16bf68b..b37069c 100644 --- a/st.c +++ b/st.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -35,10 +36,6 @@ char *argv0; #define Glyph Glyph_ #define Font Font_ -#define Draw XftDraw * -#define Colour XftColor -#define Colourmap Colormap -#define Rectangle XRectangle #if defined(__linux) #include @@ -54,6 +51,7 @@ char *argv0; #define XEMBED_FOCUS_OUT 5 /* Arbitrary sizes */ +#define UTF_INVALID 0xFFFD #define UTF_SIZ 4 #define ESC_BUF_SIZ (128*UTF_SIZ) #define ESC_ARG_SIZ 16 @@ -67,10 +65,9 @@ char *argv0; #define REDRAW_TIMEOUT (80*1000) /* 80 ms */ /* macros */ -#define SERRNO strerror(errno) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) < (b) ? (b) : (a)) -#define LEN(a) (sizeof(a) / sizeof(a[0])) +#define LEN(a) (sizeof(a) / sizeof(a)[0]) #define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) @@ -78,6 +75,7 @@ char *argv0; #define IS_SET(flag) ((term.mode & (flag)) != 0) #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000) #define CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x)) +#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) #define IS_TRUECOL(x) (1 << 24 & (x)) @@ -133,6 +131,7 @@ enum term_mode { MODE_MOUSEX10 = 131072, MODE_MOUSEMANY = 262144, MODE_BRCKTPASTE = 524288, + MODE_PRINT = 1048576, MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\ |MODE_MOUSEMANY, }; @@ -177,11 +176,15 @@ typedef unsigned int uint; typedef unsigned long ulong; typedef unsigned short ushort; +typedef XftDraw *Draw; +typedef XftColor Colour; +typedef Colormap Colourmap; + typedef struct { char c[UTF_SIZ]; /* character code */ ushort mode; /* attribute flags */ - ulong fg; /* foreground */ - ulong bg; /* background */ + uint32_t fg; /* foreground */ + uint32_t bg; /* background */ } Glyph; typedef Glyph *Line; @@ -239,7 +242,7 @@ typedef struct { Colourmap cmap; Window win; Drawable buf; - Atom xembed, wmdeletewin; + Atom xembed, wmdeletewin, netwmname, netwmpid; XIM xim; XIC xic; Draw draw; @@ -247,7 +250,8 @@ typedef struct { XSetWindowAttributes attrs; int scr; bool isfixed; /* is fixed geometry? */ - int fx, fy, fw, fh; /* fixed geometry */ + int l, t; /* left and top offset */ + int gm; /* geometry mask */ int tw, th; /* tty width and height */ int w, h; /* window width and height */ int ch; /* char height */ @@ -256,9 +260,9 @@ typedef struct { } XWindow; typedef struct { - int b; + uint b; uint mask; - char s[ESC_BUF_SIZ]; + char *s; } Mousekey; typedef struct { @@ -295,13 +299,13 @@ typedef struct { typedef union { int i; - unsigned int ui; + uint ui; float f; const void *v; } Arg; typedef struct { - unsigned int mod; + uint mod; KeySym keysym; void (*func)(const Arg *); const Arg arg; @@ -312,6 +316,9 @@ static void clippaste(const Arg *); static void numlock(const Arg *); static void selpaste(const Arg *); static void xzoom(const Arg *); +static void printsel(const Arg *); +static void printscreen(const Arg *) ; +static void toggleprinter(const Arg *); /* Config.h for applying patches and the configuration. */ #include "config.h" @@ -354,6 +361,10 @@ static void strparse(void); static void strreset(void); static int tattrset(int); +static void tprinter(char *, size_t); +static void tdumpsel(void); +static void tdumpline(int); +static void tdump(void); static void tclearregion(int, int, int, int); static void tcursor(int); static void tdeletechar(int); @@ -361,16 +372,16 @@ static void tdeleteline(int); static void tinsertblank(int); static void tinsertblankline(int); static void tmoveto(int, int); -static void tmoveato(int x, int y); +static void tmoveato(int, int); static void tnew(int, int); static void tnewline(int); -static void tputtab(bool); +static void tputtab(int); static void tputc(char *, int); static void treset(void); static int tresize(int, int); static void tscrollup(int, int); static void tscrolldown(int, int); -static void tsetattr(int*, int); +static void tsetattr(int *, int); static void tsetchar(char *, Glyph *, int, int); static void tsetscroll(int, int); static void tswapscreen(void); @@ -379,13 +390,14 @@ static void tsetdirtattr(int); static void tsetmode(bool, bool, int *, int); static void tfulldirt(void); static void techo(char *, int); -static long tdefcolor(int *, int *, int); +static int32_t tdefcolor(int *, int *, int); static void tselcs(void); static void tdeftran(char); static inline bool match(uint, uint); static void ttynew(void); static void ttyread(void); static void ttyresize(void); +static void ttysend(char *, size_t); static void ttywrite(const char *, size_t); static void xdraws(char *, Glyph, int, int, int, int); @@ -395,16 +407,17 @@ static void xdrawcursor(void); static void xinit(void); static void xloadcols(void); static int xsetcolorname(int, const char *); +static int xgeommasktogravity(int); static int xloadfont(Font *, FcPattern *); -static void xloadfonts(char *, int); +static void xloadfonts(char *, double); static int xloadfontset(Font *); static void xsettitle(char *); static void xresettitle(void); static void xsetpointermotion(int); static void xseturgency(int); -static void xsetsel(char*); +static void xsetsel(char *); static void xtermclear(int, int, int, int); -static void xunloadfont(Font *f); +static void xunloadfont(Font *); static void xunloadfonts(void); static void xresize(int, int); @@ -427,18 +440,22 @@ static void selrequest(XEvent *); static void selinit(void); static void selsort(void); static inline bool selected(int, int); +static char *getsel(void); static void selcopy(void); static void selscroll(int, int); static void selsnap(int, int *, int *, int); -static int utf8decode(char *, long *); -static int utf8encode(long *, char *); -static int utf8size(char *); -static int isfullutf8(char *, int); +static size_t utf8decode(char *, long *, size_t); +static long utf8decodebyte(char, size_t *); +static size_t utf8encode(long, char *, size_t); +static char utf8encodebyte(long, size_t); +static size_t utf8len(char *); +static size_t utf8validate(long *, size_t); static ssize_t xwrite(int, char *, size_t); static void *xmalloc(size_t); static void *xrealloc(void *, size_t); +static char *xstrdup(char *); static void (*handler[LASTEvent])(XEvent *) = { [KeyPress] = kpress, @@ -466,7 +483,7 @@ static STREscape strescseq; static int cmdfd; static pid_t pid; static Selection sel; -static int iofd = -1; +static int iofd = STDOUT_FILENO; static char **opt_cmd = NULL; static char *opt_io = NULL; static char *opt_title = NULL; @@ -476,7 +493,12 @@ static char *opt_font = NULL; static int oldbutton = 3; /* button event on startup: 3 = release */ static char *usedfont = NULL; -static int usedfontsize = 0; +static double usedfontsize = 0; + +static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; /* Font Ring Cache */ enum { @@ -527,128 +549,77 @@ xrealloc(void *p, size_t len) { return p; } -int -utf8decode(char *s, long *u) { - uchar c; - int i, n, rtn; - - rtn = 1; - c = *s; - if(~c & 0x80) { /* 0xxxxxxx */ - *u = c; - return rtn; - } else if((c & 0xE0) == 0xC0) { /* 110xxxxx */ - *u = c & 0x1F; - n = 1; - } else if((c & 0xF0) == 0xE0) { /* 1110xxxx */ - *u = c & 0x0F; - n = 2; - } else if((c & 0xF8) == 0xF0) { /* 11110xxx */ - *u = c & 0x07; - n = 3; - } else { - goto invalid; - } - - for(i = n, ++s; i > 0; --i, ++rtn, ++s) { - c = *s; - if((c & 0xC0) != 0x80) /* 10xxxxxx */ - goto invalid; - *u <<= 6; - *u |= c & 0x3F; - } - - if((n == 1 && *u < 0x80) || - (n == 2 && *u < 0x800) || - (n == 3 && *u < 0x10000) || - (*u >= 0xD800 && *u <= 0xDFFF)) { - goto invalid; - } - - return rtn; -invalid: - *u = 0xFFFD; +char * +xstrdup(char *s) { + if((s = strdup(s)) == NULL) + die("Out of memory\n"); - return rtn; + return s; } -int -utf8encode(long *u, char *s) { - uchar *sp; - ulong uc; - int i, n; - - sp = (uchar *)s; - uc = *u; - if(uc < 0x80) { - *sp = uc; /* 0xxxxxxx */ +size_t +utf8decode(char *c, long *u, size_t clen) { + size_t i, j, len, type; + long udecoded; + + *u = UTF_INVALID; + if(!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if(!BETWEEN(len, 1, UTF_SIZ)) return 1; - } else if(*u < 0x800) { - *sp = (uc >> 6) | 0xC0; /* 110xxxxx */ - n = 1; - } else if(uc < 0x10000) { - *sp = (uc >> 12) | 0xE0; /* 1110xxxx */ - n = 2; - } else if(uc <= 0x10FFFF) { - *sp = (uc >> 18) | 0xF0; /* 11110xxx */ - n = 3; - } else { - goto invalid; + for(i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if(type != 0) + return j; } + if(j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + return len; +} - for(i=n,++sp; i>0; --i,++sp) - *sp = ((uc >> 6*(i-1)) & 0x3F) | 0x80; /* 10xxxxxx */ - - return n+1; -invalid: - /* U+FFFD */ - *s++ = '\xEF'; - *s++ = '\xBF'; - *s = '\xBD'; - - return 3; +long +utf8decodebyte(char c, size_t *i) { + for(*i = 0; *i < LEN(utfmask); ++(*i)) + if(((uchar)c & utfmask[*i]) == utfbyte[*i]) + return (uchar)c & ~utfmask[*i]; + return 0; } -/* use this if your buffer is less than UTF_SIZ, it returns 1 if you can decode - UTF-8 otherwise return 0 */ -int -isfullutf8(char *s, int b) { - uchar *c1, *c2, *c3; +size_t +utf8encode(long u, char *c, size_t clen) { + size_t len, i; - c1 = (uchar *)s; - c2 = (uchar *)++s; - c3 = (uchar *)++s; - if(b < 1) { - return 0; - } else if((*c1 & 0xE0) == 0xC0 && b == 1) { - return 0; - } else if((*c1 & 0xF0) == 0xE0 && - ((b == 1) || - ((b == 2) && (*c2 & 0xC0) == 0x80))) { + len = utf8validate(&u, 0); + if(clen < len) return 0; - } else if((*c1 & 0xF8) == 0xF0 && - ((b == 1) || - ((b == 2) && (*c2 & 0xC0) == 0x80) || - ((b == 3) && (*c2 & 0xC0) == 0x80 && (*c3 & 0xC0) == 0x80))) { - return 0; - } else { - return 1; + for(i = len - 1; i != 0; --i) { + c[i] = utf8encodebyte(u, 0); + u >>= 6; } + c[0] = utf8encodebyte(u, len); + return len; } -int -utf8size(char *s) { - uchar c = *s; +char +utf8encodebyte(long u, size_t i) { + return utfbyte[i] | (u & ~utfmask[i]); +} - if(~c & 0x80) { - return 1; - } else if((c & 0xE0) == 0xC0) { - return 2; - } else if((c & 0xF0) == 0xE0) { - return 3; - } else { - return 4; - } +size_t +utf8len(char *c) { + return utf8decode(c, &(long){0}, UTF_SIZ); +} + +size_t +utf8validate(long *u, size_t i) { + if(!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) + *u = UTF_INVALID; + for(i = 1; *u > utfmax[i]; ++i) + ; + return i; } static void @@ -893,9 +864,7 @@ bpress(XEvent *e) { for(mk = mshortcuts; mk < mshortcuts + LEN(mshortcuts); mk++) { if(e->xbutton.button == mk->b && match(mk->mask, e->xbutton.state)) { - ttywrite(mk->s, strlen(mk->s)); - if(IS_SET(MODE_ECHO)) - techo(mk->s, strlen(mk->s)); + ttysend(mk->s, strlen(mk->s)); return; } } @@ -938,8 +907,8 @@ bpress(XEvent *e) { } } -void -selcopy(void) { +char * +getsel(void) { char *str, *ptr; int x, y, bufsize, size, i, ex; Glyph *gp, *last; @@ -953,17 +922,18 @@ selcopy(void) { /* append every set & selected glyph to the selection */ for(y = sel.nb.y; y < sel.ne.y + 1; y++) { gp = &term.line[y][0]; - last = gp + term.col; + last = &gp[term.col-1]; - while(--last >= gp && !(selected(last - gp, y) && \ - strcmp(last->c, " ") != 0)) - /* nothing */; + while(last >= gp && !(selected(last - gp, y) && + strcmp(last->c, " ") != 0)) { + --last; + } for(x = 0; gp <= last; x++, ++gp) { if(!selected(x, y) || (gp->mode & ATTR_WDUMMY)) continue; - size = utf8size(gp->c); + size = utf8len(gp->c); memcpy(ptr, gp->c, size); ptr += size; } @@ -997,7 +967,12 @@ selcopy(void) { } *ptr = 0; } - xsetsel(str); + return str; +} + +void +selcopy(void) { + xsetsel(getsel()); } void @@ -1031,7 +1006,7 @@ selnotify(XEvent *e) { if(IS_SET(MODE_BRCKTPASTE)) ttywrite("\033[200~", 6); - ttywrite((const char *)data, nitems * format / 8); + ttysend((char *)data, nitems * format / 8); if(IS_SET(MODE_BRCKTPASTE)) ttywrite("\033[201~", 6); XFree(data); @@ -1206,7 +1181,7 @@ sigchld(int a) { int stat = 0; if(waitpid(pid, &stat, 0) < 0) - die("Waiting for pid %hd failed: %s\n", pid, SERRNO); + die("Waiting for pid %hd failed: %s\n", pid, strerror(errno)); if(WIFEXITED(stat)) { exit(WEXITSTATUS(stat)); @@ -1222,7 +1197,7 @@ ttynew(void) { /* seems to work fine on linux, openbsd and freebsd */ if(openpty(&m, &s, NULL, NULL, &w) < 0) - die("openpty failed: %s\n", SERRNO); + die("openpty failed: %s\n", strerror(errno)); switch(pid = fork()) { case -1: @@ -1234,7 +1209,7 @@ ttynew(void) { dup2(s, STDOUT_FILENO); dup2(s, STDERR_FILENO); if(ioctl(s, TIOCSCTTY, NULL) < 0) - die("ioctl TIOCSCTTY failed: %s\n", SERRNO); + die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); close(s); close(m); execsh(); @@ -1244,6 +1219,7 @@ ttynew(void) { cmdfd = m; signal(SIGCHLD, sigchld); if(opt_io) { + term.mode |= MODE_PRINT; iofd = (!strcmp(opt_io, "-")) ? STDOUT_FILENO : open(opt_io, O_WRONLY | O_CREAT, 0666); @@ -1271,19 +1247,18 @@ ttyread(void) { char *ptr; char s[UTF_SIZ]; int charsize; /* size of utf8 char in bytes */ - long utf8c; + long unicodep; int ret; /* append read bytes to unprocessed bytes */ if((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0) - die("Couldn't read from shell: %s\n", SERRNO); + die("Couldn't read from shell: %s\n", strerror(errno)); /* process every complete utf8 char */ buflen += ret; ptr = buf; - while(buflen >= UTF_SIZ || isfullutf8(ptr,buflen)) { - charsize = utf8decode(ptr, &utf8c); - utf8encode(&utf8c, s); + while((charsize = utf8decode(ptr, &unicodep, buflen))) { + utf8encode(unicodep, s, UTF_SIZ); tputc(s, charsize); ptr += charsize; buflen -= charsize; @@ -1296,7 +1271,14 @@ ttyread(void) { void ttywrite(const char *s, size_t n) { if(write(cmdfd, s, n) == -1) - die("write error on tty: %s\n", SERRNO); + die("write error on tty: %s\n", strerror(errno)); +} + +void +ttysend(char *s, size_t n) { + ttywrite(s, n); + if(IS_SET(MODE_ECHO)) + techo(s, n); } void @@ -1308,7 +1290,7 @@ ttyresize(void) { w.ws_xpixel = xw.tw; w.ws_ypixel = xw.th; if(ioctl(cmdfd, TIOCSWINSZ, &w) < 0) - fprintf(stderr, "Couldn't set window size: %s\n", SERRNO); + fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno)); } int @@ -1418,15 +1400,13 @@ tscrolldown(int orig, int n) { LIMIT(n, 0, term.bot-orig+1); + tsetdirt(orig, term.bot-n); tclearregion(0, term.bot-n+1, term.col-1, term.bot); for(i = term.bot; i >= orig+n; i--) { temp = term.line[i]; term.line[i] = term.line[i-n]; term.line[i-n] = temp; - - term.dirty[i] = 1; - term.dirty[i-n] = 1; } selscroll(orig, n); @@ -1436,17 +1416,16 @@ void tscrollup(int orig, int n) { int i; Line temp; + LIMIT(n, 0, term.bot-orig+1); tclearregion(0, orig, term.col-1, orig+n-1); + tsetdirt(orig+n, term.bot); for(i = orig; i <= term.bot-n; i++) { - temp = term.line[i]; - term.line[i] = term.line[i+n]; - term.line[i+n] = temp; - - term.dirty[i] = 1; - term.dirty[i+n] = 1; + temp = term.line[i]; + term.line[i] = term.line[i+n]; + term.line[i+n] = temp; } selscroll(orig, -n); @@ -1562,8 +1541,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) { * The table is proudly stolen from rxvt. */ if(attr->mode & ATTR_GFX) { - if(c[0] >= 0x41 && c[0] <= 0x7e - && vt100_0[c[0] - 0x41]) { + if(BETWEEN(c[0], 0x41, 0x7e) && vt100_0[c[0] - 0x41]) { c = vt100_0[c[0] - 0x41]; } } @@ -1610,59 +1588,51 @@ tclearregion(int x1, int y1, int x2, int y2) { void tdeletechar(int n) { - int src = term.c.x + n; - int dst = term.c.x; - int size = term.col - src; + int dst, src, size; + Glyph *line; - term.dirty[term.c.y] = 1; + LIMIT(n, 0, term.col - term.c.x); - if(src >= term.col) { - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); - return; - } + dst = term.c.x; + src = term.c.x + n; + size = term.col - src; + line = term.line[term.c.y]; - memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], - size * sizeof(Glyph)); + memmove(&line[dst], &line[src], size * sizeof(Glyph)); tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); } void tinsertblank(int n) { - int src = term.c.x; - int dst = src + n; - int size = term.col - dst; + int dst, src, size; + Glyph *line; - term.dirty[term.c.y] = 1; + LIMIT(n, 0, term.col - term.c.x); - if(dst >= term.col) { - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); - return; - } + dst = term.c.x + n; + src = term.c.x; + size = term.col - dst; + line = term.line[term.c.y]; - memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], - size * sizeof(Glyph)); + memmove(&line[dst], &line[src], size * sizeof(Glyph)); tclearregion(src, term.c.y, dst - 1, term.c.y); } void tinsertblankline(int n) { - if(term.c.y < term.top || term.c.y > term.bot) - return; - - tscrolldown(term.c.y, n); + if(BETWEEN(term.c.y, term.top, term.bot)) + tscrolldown(term.c.y, n); } void tdeleteline(int n) { - if(term.c.y < term.top || term.c.y > term.bot) - return; - - tscrollup(term.c.y, n); + if(BETWEEN(term.c.y, term.top, term.bot)) + tscrollup(term.c.y, n); } -long +int32_t tdefcolor(int *attr, int *npar, int l) { - long idx = -1; + int32_t idx = -1; uint r, g, b; switch (attr[*npar + 1]) { @@ -1711,7 +1681,7 @@ tdefcolor(int *attr, int *npar, int l) { void tsetattr(int *attr, int l) { int i; - long idx; + int32_t idx; for(i = 0; i < l; i++) { switch(attr[i]) { @@ -1803,8 +1773,6 @@ tsetscroll(int t, int b) { term.bot = b; } -#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) - void tsetmode(bool priv, bool set, int *args, int narg) { int *lim, mode; @@ -1873,7 +1841,10 @@ tsetmode(bool priv, bool set, int *args, int narg) { MODBIT(term.mode, set, MODE_8BIT); break; case 1049: /* swap screen & set/restore cursor as xterm */ + if (!allowaltscreen) + break; tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); + /* FALLTHRU */ case 47: /* swap screen */ case 1047: if (!allowaltscreen) @@ -1960,6 +1931,25 @@ csihandle(void) { DEFAULT(csiescseq.arg[0], 1); tmoveto(term.c.x, term.c.y+csiescseq.arg[0]); break; + case 'i': /* MC -- Media Copy */ + switch(csiescseq.arg[0]) { + case 0: + tdump(); + break; + case 1: + tdumpline(term.c.y); + break; + case 2: + tdumpsel(); + break; + case 4: + term.mode &= ~MODE_PRINT; + break; + case 5: + term.mode |= MODE_PRINT; + break; + } + break; case 'c': /* DA -- Device Attributes */ if(csiescseq.arg[0] == 0) ttywrite(VT102ID, sizeof(VT102ID) - 1); @@ -2006,8 +1996,7 @@ csihandle(void) { break; case 'I': /* CHT -- Cursor Forward Tabulation tab stops */ DEFAULT(csiescseq.arg[0], 1); - while(csiescseq.arg[0]--) - tputtab(1); + tputtab(csiescseq.arg[0]); break; case 'J': /* ED -- Clear screen */ selclear(NULL); @@ -2075,8 +2064,7 @@ csihandle(void) { break; case 'Z': /* CBT -- Cursor Backward Tabulation tab stops */ DEFAULT(csiescseq.arg[0], 1); - while(csiescseq.arg[0]--) - tputtab(0); + tputtab(-csiescseq.arg[0]); break; case 'd': /* VPA -- Move to */ DEFAULT(csiescseq.arg[0], 1); @@ -2145,20 +2133,21 @@ csireset(void) { void strhandle(void) { char *p = NULL; - int i, j, narg; + int j, narg, par; strparse(); narg = strescseq.narg; + par = atoi(strescseq.args[0]); switch(strescseq.type) { case ']': /* OSC -- Operating System Command */ - switch(i = atoi(strescseq.args[0])) { + switch(par) { case 0: case 1: case 2: if(narg > 1) xsettitle(strescseq.args[1]); - break; + return; case 4: /* color set */ if(narg < 3) break; @@ -2175,25 +2164,20 @@ strhandle(void) { */ redraw(0); } - break; - default: - fprintf(stderr, "erresc: unknown str "); - strdump(); - break; + return; } break; case 'k': /* old title set compatibility */ xsettitle(strescseq.args[0]); - break; + return; case 'P': /* DSC -- Device Control String */ case '_': /* APC -- Application Program Command */ case '^': /* PM -- Privacy Message */ - default: - fprintf(stderr, "erresc: unknown str "); - strdump(); - /* die(""); */ - break; + return; } + + fprintf(stderr, "erresc: unknown str "); + strdump(); } void @@ -2237,19 +2221,75 @@ strreset(void) { } void -tputtab(bool forward) { +tprinter(char *s, size_t len) { + if(iofd != -1 && xwrite(iofd, s, len) < 0) { + fprintf(stderr, "Error writing in %s:%s\n", + opt_io, strerror(errno)); + close(iofd); + iofd = -1; + } +} + +void +toggleprinter(const Arg *arg) { + term.mode ^= MODE_PRINT; +} + +void +printscreen(const Arg *arg) { + tdump(); +} + +void +printsel(const Arg *arg) { + tdumpsel(); +} + +void +tdumpsel(void) { + char *ptr; + + if((ptr = getsel())) { + tprinter(ptr, strlen(ptr)); + free(ptr); + } +} + +void +tdumpline(int n) { + Glyph *bp, *end; + + bp = &term.line[n][0]; + end = &bp[term.col-1]; + while(end > bp && !strcmp(" ", end->c)) + --end; + if(bp != end || strcmp(bp->c, " ")) { + for( ;bp <= end; ++bp) + tprinter(bp->c, strlen(bp->c)); + } + tprinter("\n", 1); +} + +void +tdump(void) { + int i; + + for(i = 0; i < term.row; ++i) + tdumpline(i); +} + +void +tputtab(int n) { uint x = term.c.x; - if(forward) { - if(x == term.col) - return; - for(++x; x < term.col && !term.tabs[x]; ++x) - /* nothing */ ; - } else { - if(x == 0) - return; - for(--x; x > 0 && !term.tabs[x]; --x) - /* nothing */ ; + if(n > 0) { + while(x < term.col && n--) + for(++x; x < term.col && !term.tabs[x]; ++x) + /* nothing */ ; + } else if(n < 0) { + while(x > 0 && n++) + for(--x; x > 0 && !term.tabs[x]; --x) + /* nothing */ ; } tmoveto(x, term.c.y); } @@ -2259,12 +2299,9 @@ techo(char *buf, int len) { for(; len > 0; buf++, len--) { char c = *buf; - if(c == '\033') { /* escape */ - tputc("^", 1); - tputc("[", 1); - } else if(c < '\x20') { /* control code */ + if(c < 0x20 || c == 0177) { /* control code */ if(c != '\n' && c != '\r' && c != '\t') { - c |= '\x40'; + c ^= '\x40'; tputc("^", 1); } tputc(&c, 1); @@ -2297,34 +2334,27 @@ tdeftran(char ascii) { void tselcs(void) { - if (term.trantbl[term.charset] == CS_GRAPHIC0) - term.c.attr.mode |= ATTR_GFX; - else - term.c.attr.mode &= ~ATTR_GFX; + MODBIT(term.c.attr.mode, + term.trantbl[term.charset] == CS_GRAPHIC0, + ATTR_GFX); } void tputc(char *c, int len) { uchar ascii = *c; bool control = ascii < '\x20' || ascii == 0177; - long u8char; + long unicodep; int width; if(len == 1) { width = 1; } else { - utf8decode(c, &u8char); - width = wcwidth(u8char); + utf8decode(c, &unicodep, UTF_SIZ); + width = wcwidth(unicodep); } - if(iofd != -1) { - if(xwrite(iofd, c, len) < 0) { - fprintf(stderr, "Error writing in %s:%s\n", - opt_io, strerror(errno)); - close(iofd); - iofd = -1; - } - } + if(IS_SET(MODE_PRINT)) + tprinter(c, len); /* * STR sequences must be checked before anything else @@ -2644,7 +2674,9 @@ tresize(int col, int row) { if(0 < col && minrow < row) { tclearregion(0, minrow, col - 1, row - 1); } + tcursor(CURSOR_SAVE); tswapscreen(); + tcursor(CURSOR_LOAD); } while(orig != term.line); return (slide > 0); @@ -2717,10 +2749,10 @@ int xsetcolorname(int x, const char *name) { XRenderColor color = { .alpha = 0xffff }; Colour colour; - if (x < 0 || x > LEN(colorname)) + if(!BETWEEN(x, 0, LEN(colorname))) return -1; if(!name) { - if(16 <= x && x < 16 + 216) { + if(BETWEEN(x, 16, 16 + 215)) { int r = (x - 16) / 36, g = ((x - 16) % 36) / 6, b = (x - 16) % 6; color.red = sixd_to_16bit(r); color.green = sixd_to_16bit(g); @@ -2729,7 +2761,7 @@ xsetcolorname(int x, const char *name) { return 0; /* something went wrong */ dc.col[x] = colour; return 1; - } else if (16 + 216 <= x && x < 256) { + } else if(BETWEEN(x, 16 + 216, 255)) { color.red = color.green = color.blue = 0x0808 + 0x0a0a * (x - (16 + 216)); if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour)) return 0; /* something went wrong */ @@ -2772,25 +2804,45 @@ xhints(void) { XSizeHints *sizeh = NULL; sizeh = XAllocSizeHints(); - if(xw.isfixed == False) { - sizeh->flags = PSize | PResizeInc | PBaseSize; - sizeh->height = xw.h; - sizeh->width = xw.w; - sizeh->height_inc = xw.ch; - sizeh->width_inc = xw.cw; - sizeh->base_height = 2 * borderpx; - sizeh->base_width = 2 * borderpx; - } else { - sizeh->flags = PMaxSize | PMinSize; - sizeh->min_width = sizeh->max_width = xw.fw; - sizeh->min_height = sizeh->max_height = xw.fh; - } - XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, &class); + sizeh->flags = PSize | PResizeInc | PBaseSize; + sizeh->height = xw.h; + sizeh->width = xw.w; + sizeh->height_inc = xw.ch; + sizeh->width_inc = xw.cw; + sizeh->base_height = 2 * borderpx; + sizeh->base_width = 2 * borderpx; + if(xw.isfixed == True) { + sizeh->flags |= PMaxSize | PMinSize; + sizeh->min_width = sizeh->max_width = xw.w; + sizeh->min_height = sizeh->max_height = xw.h; + } + if(xw.gm & (XValue|YValue)) { + sizeh->flags |= USPosition | PWinGravity; + sizeh->x = xw.l; + sizeh->y = xw.t; + sizeh->win_gravity = xgeommasktogravity(xw.gm); + } + + XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, + &class); XFree(sizeh); } int +xgeommasktogravity(int mask) { + switch(mask & (XNegative|YNegative)) { + case 0: + return NorthWestGravity; + case XNegative: + return NorthEastGravity; + case YNegative: + return SouthWestGravity; + } + return SouthEastGravity; +} + +int xloadfont(Font *f, FcPattern *pattern) { FcPattern *match; FcResult result; @@ -2819,9 +2871,9 @@ xloadfont(Font *f, FcPattern *pattern) { } void -xloadfonts(char *fontstr, int fontsize) { +xloadfonts(char *fontstr, double fontsize) { FcPattern *pattern; - FcResult result; + FcResult r_sz, r_psz; double fontval; if(fontstr[0] == '-') { @@ -2835,12 +2887,16 @@ xloadfonts(char *fontstr, int fontsize) { if(fontsize > 0) { FcPatternDel(pattern, FC_PIXEL_SIZE); + FcPatternDel(pattern, FC_SIZE); FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize); usedfontsize = fontsize; } else { - result = FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval); - if(result == FcResultMatch) { - usedfontsize = (int)fontval; + r_psz = FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval); + r_sz = FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval); + if(r_psz == FcResultMatch) { + usedfontsize = fontval; + } else if(r_sz == FcResultMatch) { + usedfontsize = -1; } else { /* * Default font size is 12, if none given. This is to @@ -2857,6 +2913,12 @@ xloadfonts(char *fontstr, int fontsize) { if(xloadfont(&dc.font, pattern)) die("st: can't open font %s\n", fontstr); + if(usedfontsize < 0) { + FcPatternGetDouble(dc.font.match->pattern, + FC_PIXEL_SIZE, 0, &fontval); + usedfontsize = fontval; + } + /* Setting character width and height. */ xw.cw = CEIL(dc.font.width * cwscale); xw.ch = CEIL(dc.font.height * chscale); @@ -2925,7 +2987,7 @@ xinit(void) { XGCValues gcvalues; Cursor cursor; Window parent; - int sw, sh; + pid_t thispid = getpid(); if(!(xw.dpy = XOpenDisplay(NULL))) die("Can't open display\n"); @@ -2944,23 +3006,12 @@ xinit(void) { xloadcols(); /* adjust fixed window geometry */ - if(xw.isfixed) { - sw = DisplayWidth(xw.dpy, xw.scr); - sh = DisplayHeight(xw.dpy, xw.scr); - if(xw.fx < 0) - xw.fx = sw + xw.fx - xw.fw - 1; - if(xw.fy < 0) - xw.fy = sh + xw.fy - xw.fh - 1; - - xw.h = xw.fh; - xw.w = xw.fw; - } else { - /* window - default size */ - xw.h = 2 * borderpx + term.row * xw.ch; - xw.w = 2 * borderpx + term.col * xw.cw; - xw.fx = 0; - xw.fy = 0; - } + xw.w = 2 * borderpx + term.col * xw.cw; + xw.h = 2 * borderpx + term.row * xw.ch; + if(xw.gm & XNegative) + xw.l += DisplayWidth(xw.dpy, xw.scr) - xw.w - 2; + if(xw.gm & YNegative) + xw.t += DisplayWidth(xw.dpy, xw.scr) - xw.h - 2; /* Events */ xw.attrs.background_pixel = dc.col[defaultbg].pixel; @@ -2973,7 +3024,7 @@ xinit(void) { parent = opt_embed ? strtol(opt_embed, NULL, 0) : \ XRootWindow(xw.dpy, xw.scr); - xw.win = XCreateWindow(xw.dpy, parent, xw.fx, xw.fy, + xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput, xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask | CWColormap, &xw.attrs); @@ -3017,12 +3068,17 @@ xinit(void) { xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); + xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False); XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1); + xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False); + XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, + PropModeReplace, (uchar *)&thispid, 1); + xresettitle(); XMapWindow(xw.dpy, xw.win); xhints(); - XSync(xw.dpy, 0); + XSync(xw.dpy, False); } void @@ -3032,7 +3088,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { int frcflags; int u8fl, u8fblen, u8cblen, doesexist; char *u8c, *u8fs; - long u8char; + long unicodep; Font *font = &dc.font; FcResult fcres; FcPattern *fcpattern, *fontpattern; @@ -3040,7 +3096,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { FcCharSet *fccharset; Colour *fg, *bg, *temp, revfg, revbg, truefg, truebg; XRenderColor colfg, colbg; - Rectangle r; + XRectangle r; int oneatatime; frcflags = FRC_NORMAL; @@ -3059,7 +3115,9 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { if(base.fg == defaultfg) base.fg = defaultunderline; } + if(IS_TRUECOL(base.fg)) { + colfg.alpha = 0xffff; colfg.red = TRUERED(base.fg); colfg.green = TRUEGREEN(base.fg); colfg.blue = TRUEBLUE(base.fg); @@ -3070,6 +3128,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { } if(IS_TRUECOL(base.bg)) { + colbg.alpha = 0xffff; colbg.green = TRUEGREEN(base.bg); colbg.red = TRUERED(base.bg); colbg.blue = TRUEBLUE(base.bg); @@ -3079,8 +3138,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { bg = &dc.col[base.bg]; } - - if(base.mode & ATTR_BOLD) { if(BETWEEN(base.fg, 0, 7)) { /* basic system colors */ @@ -3110,7 +3167,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { colfg.green = ~fg->color.green; colfg.blue = ~fg->color.blue; colfg.alpha = fg->color.alpha; - XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, + &revfg); fg = &revfg; } @@ -3121,7 +3179,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { colbg.green = ~bg->color.green; colbg.blue = ~bg->color.blue; colbg.alpha = bg->color.alpha; - XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &revbg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, + &revbg); bg = &revbg; } } @@ -3172,11 +3231,11 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { oneatatime = font->width != xw.cw; for(;;) { u8c = s; - u8cblen = utf8decode(s, &u8char); + u8cblen = utf8decode(s, &unicodep, UTF_SIZ); s += u8cblen; bytelen -= u8cblen; - doesexist = XftCharExists(xw.dpy, font->match, u8char); + doesexist = XftCharExists(xw.dpy, font->match, unicodep); if(oneatatime || !doesexist || bytelen <= 0) { if(oneatatime || bytelen <= 0) { if(doesexist) { @@ -3201,14 +3260,14 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { u8fblen += u8cblen; } if(doesexist) { - if (oneatatime) + if(oneatatime) continue; break; } /* Search the font cache. */ for(i = 0; i < frclen; i++) { - if(XftCharExists(xw.dpy, frc[i].font, u8char) + if(XftCharExists(xw.dpy, frc[i].font, unicodep) && frc[i].flags == frcflags) { break; } @@ -3224,11 +3283,13 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { * Nothing was found in the cache. Now use * some dozen of Fontconfig calls to get the * font for one single character. + * + * Xft and fontconfig are design failures. */ fcpattern = FcPatternDuplicate(font->pattern); fccharset = FcCharSetCreate(); - FcCharSetAddChar(fccharset, u8char); + FcCharSetAddChar(fccharset, unicodep); FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); FcPatternAddBool(fcpattern, FC_SCALABLE, @@ -3264,10 +3325,16 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { xp, winy + frc[i].font->ascent, (FcChar8 *)u8c, u8cblen); - xp += xw.cw * wcwidth(u8char); + xp += xw.cw * wcwidth(unicodep); } /* + * This is how the loop above actually should be. Why does the + * application have to care about font details? + * + * I have to repeat: Xft and Fontconfig are design failures. + */ + /* XftDrawStringUtf8(xw.draw, fg, font->set, winx, winy + font->ascent, (FcChar8 *)s, bytelen); */ @@ -3301,7 +3368,7 @@ xdrawcursor(void) { memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ); /* remove the old cursor */ - sl = utf8size(term.line[oldy][oldx].c); + sl = utf8len(term.line[oldy][oldx].c); width = (term.line[oldy][oldx].mode & ATTR_WIDE)? 2 : 1; xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, width, sl); @@ -3315,7 +3382,7 @@ xdrawcursor(void) { g.bg = defaultfg; } - sl = utf8size(g.c); + sl = utf8len(g.c); width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\ ? 2 : 1; xdraws(g.c, g, term.c.x, term.c.y, width, sl); @@ -3349,6 +3416,7 @@ xsettitle(char *p) { Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, &prop); XSetWMName(xw.dpy, xw.win, &prop); + XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname); XFree(prop.value); } @@ -3361,7 +3429,6 @@ void redraw(int timeout) { struct timespec tv = {0, timeout * 1000}; - tfulldirt(); draw(); if(timeout > 0) { @@ -3386,9 +3453,9 @@ drawregion(int x1, int y1, int x2, int y2) { Glyph base, new; char buf[DRAW_BUF_SIZ]; bool ena_sel = sel.ob.x != -1; - long u8char; + long unicodep; - if(sel.alt ^ IS_SET(MODE_ALTSCREEN)) + if(sel.alt != IS_SET(MODE_ALTSCREEN)) ena_sel = 0; if(!(xw.state & WIN_VISIBLE)) @@ -3418,7 +3485,7 @@ drawregion(int x1, int y1, int x2, int y2) { base = new; } - sl = utf8decode(new.c, &u8char); + sl = utf8decode(new.c, &unicodep, UTF_SIZ); memcpy(buf+ib, new.c, sl); ib += sl; ic += (new.mode & ATTR_WIDE)? 2 : 1; @@ -3495,15 +3562,7 @@ focus(XEvent *ev) { static inline bool match(uint mask, uint state) { - state &= ~ignoremod; - - if(mask == XK_NO_MOD && state) - return false; - if(mask != XK_ANY_MOD && mask != XK_NO_MOD && !state) - return false; - if(mask == XK_ANY_MOD) - return true; - return state == mask; + return mask == XK_ANY_MOD || mask == (state & ~ignoremod); } void @@ -3533,25 +3592,16 @@ kmap(KeySym k, uint state) { if(!match(kp->mask, state)) continue; - if(kp->appkey > 0) { - if(!IS_SET(MODE_APPKEYPAD)) - continue; - if(term.numlock && kp->appkey == 2) - continue; - } else if(kp->appkey < 0 && IS_SET(MODE_APPKEYPAD)) { + if(IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0) + continue; + if(term.numlock && kp->appkey == 2) continue; - } - if((kp->appcursor < 0 && IS_SET(MODE_APPCURSOR)) || - (kp->appcursor > 0 - && !IS_SET(MODE_APPCURSOR))) { + if(IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0) continue; - } - if((kp->crlf < 0 && IS_SET(MODE_CRLF)) || - (kp->crlf > 0 && !IS_SET(MODE_CRLF))) { + if(IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0) continue; - } return kp->s; } @@ -3573,7 +3623,6 @@ kpress(XEvent *ev) { return; len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status); - e->state &= ~Mod2Mask; /* 1. shortcuts */ for(bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { if(ksym == bp->keysym && match(bp->mod, e->state)) { @@ -3584,10 +3633,7 @@ kpress(XEvent *ev) { /* 2. custom keys from config.h */ if((customkey = kmap(ksym, e->state))) { - len = strlen(customkey); - ttywrite(customkey, len); - if(IS_SET(MODE_ECHO)) - techo(customkey, len); + ttysend(customkey, strlen(customkey)); return; } @@ -3598,7 +3644,7 @@ kpress(XEvent *ev) { if(IS_SET(MODE_8BIT)) { if(*buf < 0177) { c = *buf | 0x80; - len = utf8encode(&c, buf); + len = utf8encode(c, buf, UTF_SIZ); } } else { buf[1] = buf[0]; @@ -3606,9 +3652,7 @@ kpress(XEvent *ev) { len = 2; } } - ttywrite(buf, len); - if(IS_SET(MODE_ECHO)) - techo(buf, len); + ttysend(buf, len); } @@ -3676,16 +3720,15 @@ run(void) { } } - if(!xw.isfixed) - cresize(w, h); - else - cresize(xw.fw, xw.fh); ttynew(); + cresize(w, h); - gettimeofday(&lastblink, NULL); gettimeofday(&last, NULL); + lastblink = last; for(xev = actionfps;;) { + long deltatime; + FD_ZERO(&rfd); FD_SET(cmdfd, &rfd); FD_SET(xfd, &rfd); @@ -3693,7 +3736,7 @@ run(void) { if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv) < 0) { if(errno == EINTR) continue; - die("select failed: %s\n", SERRNO); + die("select failed: %s\n", strerror(errno)); } if(FD_ISSET(cmdfd, &rfd)) { ttyread(); @@ -3716,11 +3759,12 @@ run(void) { if(blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) { tsetdirtattr(ATTR_BLINK); term.mode ^= MODE_BLINK; - gettimeofday(&lastblink, NULL); + lastblink = now; dodraw = 1; } - if(TIMEDIFF(now, last) \ - > (xev? (1000/xfps) : (1000/actionfps))) { + deltatime = TIMEDIFF(now, last); + if(deltatime > (xev? (1000/xfps) : (1000/actionfps)) + || deltatime < 0) { dodraw = 1; last = now; } @@ -3760,18 +3804,17 @@ run(void) { void usage(void) { - die("%s " VERSION " (c) 2010-2013 st engineers\n" \ + die("%s " VERSION " (c) 2010-2014 st engineers\n" \ "usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]" \ " [-t title] [-w windowid] [-e command ...]\n", argv0); } int main(int argc, char *argv[]) { - int bitm, xr, yr; - uint wr, hr; char *titles; + uint cols = 80, rows = 24; - xw.fw = xw.fh = xw.fx = xw.fy = 0; + xw.l = xw.t = 0; xw.isfixed = False; ARGBEGIN { @@ -3786,7 +3829,7 @@ main(int argc, char *argv[]) { if(argc > 1) { opt_cmd = &argv[1]; if(argv[1] != NULL && opt_title == NULL) { - titles = strdup(argv[1]); + titles = xstrdup(argv[1]); opt_title = basename(titles); } } @@ -3795,22 +3838,11 @@ main(int argc, char *argv[]) { opt_font = EARGF(usage()); break; case 'g': - bitm = XParseGeometry(EARGF(usage()), &xr, &yr, &wr, &hr); - if(bitm & XValue) - xw.fx = xr; - if(bitm & YValue) - xw.fy = yr; - if(bitm & WidthValue) - xw.fw = (int)wr; - if(bitm & HeightValue) - xw.fh = (int)hr; - if(bitm & XNegative && xw.fx == 0) - xw.fx = -1; - if(bitm & YNegative && xw.fy == 0) - xw.fy = -1; - - if(xw.fh != 0 && xw.fw != 0) - xw.isfixed = True; + xw.gm = XParseGeometry(EARGF(usage()), + &xw.l, &xw.t, &cols, &rows); + break; + case 'i': + xw.isfixed = True; break; case 'o': opt_io = EARGF(usage()); @@ -3829,7 +3861,7 @@ main(int argc, char *argv[]) { run: setlocale(LC_CTYPE, ""); XSetLocaleModifiers(""); - tnew(80, 24); + tnew(cols? cols : 1, rows? rows : 1); xinit(); selinit(); run();