X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=st.c;h=5703e964ab644596bd5ed6e44e04cf447a10a740;hb=71b09ec4f172da9a89be2add54b5b94da8af3bea;hp=16c64b1cbbdfebb91660f9f838a8ee345c47a794;hpb=b16b5d77d31c4c6b2577ab0986e85b43baaf834a;p=st.git diff --git a/st.c b/st.c index 16c64b1..5703e96 100644 --- a/st.c +++ b/st.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,8 @@ #define REDRAW_TIMEOUT (80*1000) /* 80 ms */ +/* macros */ +#define CLEANMASK(mask) (mask & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) #define SERRNO strerror(errno) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) < (b) ? (b) : (a)) @@ -72,6 +75,8 @@ #define X2COL(x) (((x) - BORDER)/xw.cw) #define Y2ROW(y) (((y) - BORDER)/xw.ch) +#define VT102ID "\033[?6c" + enum glyph_attribute { ATTR_NULL = 0, ATTR_REVERSE = 1, @@ -121,6 +126,7 @@ enum escape_state { ESC_STR = 4, /* DSC, OSC, PM, APC */ ESC_ALTCHARSET = 8, ESC_STR_END = 16, /* a final string was encountered */ + ESC_TEST = 32, /* Enter in test mode */ }; enum window_state { @@ -234,6 +240,24 @@ typedef struct { struct timeval tclick2; } Selection; +typedef union { + int i; + unsigned int ui; + float f; + const void *v; +} Arg; + +typedef struct { + unsigned int mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; +} Shortcut; + +/* function definitions used in config.h */ +static void xzoom(const Arg *); + +/* Config.h for applying patches and the configuration. */ #include "config.h" /* Font structure */ @@ -287,7 +311,7 @@ static int tresize(int, int); static void tscrollup(int, int); static void tscrolldown(int, int); static void tsetattr(int*, int); -static void tsetchar(char*); +static void tsetchar(char *, Glyph *, int, int); static void tsetscroll(int, int); static void tswapscreen(void); static void tsetdirt(int, int); @@ -317,6 +341,7 @@ static void unmap(XEvent *); static char *kmap(KeySym, uint); static void kpress(XEvent *); static void cmessage(XEvent *); +static void cresize(int width, int height); static void resize(XEvent *); static void focus(XEvent *); static void brelease(XEvent *); @@ -337,10 +362,10 @@ static int utf8encode(long *, char *); static int utf8size(char *); static int isfullutf8(char *, int); +static ssize_t xwrite(int, char *, size_t); static void *xmalloc(size_t); static void *xrealloc(void *, size_t); static void *xcalloc(size_t nmemb, size_t size); -static char *smstrcat(char *, ...); static void (*handler[LASTEvent])(XEvent *) = { [KeyPress] = kpress, @@ -376,6 +401,23 @@ static char *opt_embed = NULL; static char *opt_class = NULL; static char *opt_font = NULL; +static char *usedfont = NULL; +static int usedfontsize = 0; + +ssize_t +xwrite(int fd, char *s, size_t len) { + size_t aux = len; + + while(len > 0) { + ssize_t r = write(fd, s, len); + if(r < 0) + return r; + len -= r; + s += r; + } + return aux; +} + void * xmalloc(size_t len) { void *p = malloc(len); @@ -404,44 +446,6 @@ xcalloc(size_t nmemb, size_t size) { return p; } -char * -smstrcat(char *src, ...) -{ - va_list fmtargs; - char *ret, *p, *v; - int len, slen, flen; - - len = slen = strlen(src); - - va_start(fmtargs, src); - for(;;) { - v = va_arg(fmtargs, char *); - if(v == NULL) - break; - len += strlen(v); - } - va_end(fmtargs); - - p = ret = xmalloc(len+1); - memmove(p, src, slen); - p += slen; - - va_start(fmtargs, src); - for(;;) { - v = va_arg(fmtargs, char *); - if(v == NULL) - break; - flen = strlen(v); - memmove(p, v, flen); - p += flen; - } - va_end(fmtargs); - - ret[len] = '\0'; - - return ret; -} - int utf8decode(char *s, long *u) { uchar c; @@ -659,7 +663,7 @@ bpress(XEvent *e) { void selcopy(void) { - char *str, *ptr, *p; + char *str, *ptr; int x, y, bufsize, is_selected = 0, size; Glyph *gp; @@ -674,11 +678,12 @@ selcopy(void) { for(x = 0; x < term.col; x++) { gp = &term.line[y][x]; - if(!(is_selected = selected(x, y))) + if(!(is_selected = selected(x, y)) + || !(gp->state & GLYPH_SET)) { continue; - p = (gp->state & GLYPH_SET) ? gp->c : " "; - size = utf8size(p); - memcpy(ptr, p, size); + } + size = utf8size(gp->c); + memcpy(ptr, gp->c, size); ptr += size; } /* \n at the end of every selected line except for the last one */ @@ -861,11 +866,23 @@ void execsh(void) { char **args; char *envshell = getenv("SHELL"); + const struct passwd *pass = getpwuid(getuid()); + char buf[sizeof(long) * 8 + 1]; unsetenv("COLUMNS"); unsetenv("LINES"); unsetenv("TERMCAP"); + if(pass) { + setenv("LOGNAME", pass->pw_name, 1); + setenv("USER", pass->pw_name, 1); + setenv("SHELL", pass->pw_shell, 0); + setenv("HOME", pass->pw_dir, 0); + } + + snprintf(buf, sizeof(buf), "%lu", xw.win); + setenv("WINDOWID", buf, 1); + signal(SIGCHLD, SIG_DFL); signal(SIGHUP, SIG_DFL); signal(SIGINT, SIG_DFL); @@ -875,7 +892,7 @@ execsh(void) { DEFAULT(envshell, SHELL); putenv("TERM="TNAME); - args = opt_cmd ? opt_cmd : (char*[]){envshell, "-i", NULL}; + args = opt_cmd ? opt_cmd : (char *[]){envshell, "-i", NULL}; execvp(args[0], args); exit(EXIT_FAILURE); } @@ -923,13 +940,12 @@ ttynew(void) { cmdfd = m; signal(SIGCHLD, sigchld); if(opt_io) { - if(!strcmp(opt_io, "-")) { - iofd = STDOUT_FILENO; - } else { - if((iofd = open(opt_io, O_WRONLY | O_CREAT, 0666)) < 0) { - fprintf(stderr, "Error opening %s:%s\n", - opt_io, strerror(errno)); - } + iofd = (!strcmp(opt_io, "-")) ? + STDOUT_FILENO : + open(opt_io, O_WRONLY | O_CREAT, 0666); + if(iofd < 0) { + fprintf(stderr, "Error opening %s:%s\n", + opt_io, strerror(errno)); } } } @@ -1180,8 +1196,8 @@ tmoveto(int x, int y) { } void -tsetchar(char *c) { - char *vt100_0[62] = { /* 0x41 - 0x7e */ +tsetchar(char *c, Glyph *attr, int x, int y) { + static char *vt100_0[62] = { /* 0x41 - 0x7e */ "↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */ 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ 0, 0, 0, 0, 0, 0, 0, 0, /* P - W */ @@ -1195,17 +1211,17 @@ tsetchar(char *c) { /* * The table is proudly stolen from rxvt. */ - if(term.c.attr.mode & ATTR_GFX) { + if(attr->mode & ATTR_GFX) { if(c[0] >= 0x41 && c[0] <= 0x7e && vt100_0[c[0] - 0x41]) { c = vt100_0[c[0] - 0x41]; } } - term.dirty[term.c.y] = 1; - term.line[term.c.y][term.c.x] = term.c.attr; - memcpy(term.line[term.c.y][term.c.x].c, c, UTF_SIZ); - term.line[term.c.y][term.c.x].state |= GLYPH_SET; + term.dirty[y] = 1; + term.line[y][x] = *attr; + memcpy(term.line[y][x].c, c, UTF_SIZ); + term.line[y][x].state |= GLYPH_SET; } void @@ -1510,6 +1526,10 @@ csihandle(void) { DEFAULT(csiescseq.arg[0], 1); tmoveto(term.c.x, term.c.y+csiescseq.arg[0]); break; + case 'c': /* DA -- Device Attributes */ + if(csiescseq.arg[0] == 0) + ttywrite(VT102ID, sizeof(VT102ID) - 1); + break; case 'C': /* CUF -- Cursor Forward */ case 'a': DEFAULT(csiescseq.arg[0], 1); @@ -1786,8 +1806,14 @@ tputc(char *c, int len) { uchar ascii = *c; bool control = ascii < '\x20' || ascii == 0177; - if(iofd != -1) - write(iofd, c, len); + if(iofd != -1) { + if (xwrite(iofd, c, len) < 0) { + fprintf(stderr, "Error writting in %s:%s\n", + opt_io, strerror(errno)); + close(iofd); + iofd = -1; + } + } /* * STR sequences must be checked before of anything * because it can use some control codes as part of the sequence @@ -1887,11 +1913,25 @@ tputc(char *c, int len) { fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii); } term.esc = 0; + } else if(term.esc & ESC_TEST) { + if(ascii == '8') { /* DEC screen alignment test. */ + char E[UTF_SIZ] = "E"; + int x, y; + + for(x = 0; x < term.col; ++x) { + for(y = 0; y < term.row; ++y) + tsetchar(E, &term.c.attr, x, y); + } + } + term.esc = 0; } else { switch(ascii) { case '[': term.esc |= ESC_CSI; break; + case '#': + term.esc |= ESC_TEST; + break; case 'P': /* DCS -- Device Control String */ case '_': /* APC -- Application Program Command */ case '^': /* PM -- Privacy Message */ @@ -1933,6 +1973,10 @@ tputc(char *c, int len) { } term.esc = 0; break; + case 'Z': /* DECID -- Identify Terminal */ + ttywrite(VT102ID, sizeof(VT102ID) - 1); + term.esc = 0; + break; case 'c': /* RIS -- Reset to inital state */ treset(); term.esc = 0; @@ -1978,7 +2022,7 @@ tputc(char *c, int len) { sel.bx = -1; if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT) tnewline(1); /* always go to first col */ - tsetchar(c); + tsetchar(c, &term.c.attr, term.c.x, term.c.y); if(term.c.x+1 < term.col) tmoveto(term.c.x+1, term.c.y); else @@ -2047,7 +2091,8 @@ tresize(int col, int row) { *bp = 1; } /* update terminal size */ - term.col = col, term.row = row; + term.col = col; + term.row = row; /* make use of the LIMIT in tmoveto */ tmoveto(term.c.x, term.c.y); /* reset scrolling region */ @@ -2147,22 +2192,17 @@ xhints(void) { XFree(sizeh); } -void -xinitfont(Font *f, char *fontstr) { - FcPattern *pattern, *match; +int +xloadfont(Font *f, FcPattern *pattern) { + FcPattern *match; FcResult result; - pattern = FcNameParse((FcChar8 *)fontstr); - if(!pattern) - die("st: can't open font %s\n", fontstr); - match = XftFontMatch(xw.dpy, xw.scr, pattern, &result); - FcPatternDestroy(pattern); if(!match) - die("st: can't open font %s\n", fontstr); + return 1; if(!(f->xft_set = XftFontOpenPattern(xw.dpy, match))) { FcPatternDestroy(match); - die("st: can't open font %s.\n", fontstr); + return 1; } f->ascent = f->xft_set->ascent; @@ -2172,27 +2212,68 @@ xinitfont(Font *f, char *fontstr) { f->height = f->xft_set->height; f->width = f->lbearing + f->rbearing; + + return 0; } void -initfonts(char *fontstr) { - char *fstr; +xloadfonts(char *fontstr, int fontsize) { + FcPattern *pattern; + FcResult result; + double fontval; + + pattern = FcNameParse((FcChar8 *)fontstr); + if(!pattern) + die("st: can't open font %s\n", fontstr); - xinitfont(&dc.font, fontstr); + if(fontsize > 0) { + FcPatternDel(pattern, FC_PIXEL_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; + } else { + /* + * Default font size is 12, if none given. This is to + * have a known usedfontsize value. + */ + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12); + usedfontsize = 12; + } + } + + if(xloadfont(&dc.font, pattern)) + die("st: can't open font %s\n", fontstr); + + /* Setting character width and height. */ xw.cw = dc.font.width; xw.ch = dc.font.height; - fstr = smstrcat(fontstr, ":weight=bold", NULL); - xinitfont(&dc.bfont, fstr); - free(fstr); + FcPatternDel(pattern, FC_WEIGHT); + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + if(xloadfont(&dc.bfont, pattern)) + die("st: can't open font %s\n", fontstr); - fstr = smstrcat(fontstr, ":slant=italic,oblique", NULL); - xinitfont(&dc.ifont, fstr); - free(fstr); + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + if(xloadfont(&dc.ibfont, pattern)) + die("st: can't open font %s\n", fontstr); - fstr = smstrcat(fontstr, ":weight=bold:slant=italic,oblique", NULL); - xinitfont(&dc.ibfont, fstr); - free(fstr); + FcPatternDel(pattern, FC_WEIGHT); + if(xloadfont(&dc.ifont, pattern)) + die("st: can't open font %s\n", fontstr); + + FcPatternDestroy(pattern); +} + +void +xzoom(const Arg *arg) +{ + xloadfonts(usedfont, usedfontsize + arg->i); + cresize(0, 0); + draw(); } void @@ -2208,7 +2289,8 @@ xinit(void) { xw.vis = XDefaultVisual(xw.dpy, xw.scr); /* font */ - initfonts((opt_font != NULL)? opt_font : FONT); + usedfont = (opt_font == NULL)? FONT : opt_font; + xloadfonts(usedfont, 0); /* colors */ xw.cmap = XDefaultColormap(xw.dpy, xw.scr); @@ -2310,7 +2392,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { * Those ranges will not be brightened: * 8 - 15 – bright system colors * 196 - 231 – highest 256 color cube - * 252 - 255 – brightest colors in grescale + * 252 - 255 – brightest colors in greyscale */ font = &dc.bfont; } @@ -2544,11 +2626,8 @@ void kpress(XEvent *ev) { XKeyEvent *e = &ev->xkey; KeySym ksym; - char buf[32]; - char *customkey; - int len; - int meta; - int shift; + char buf[32], *customkey; + int len, meta, shift, i; Status status; if (IS_SET(MODE_KBDLOCK)) @@ -2558,7 +2637,17 @@ kpress(XEvent *ev) { shift = e->state & ShiftMask; len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status); - /* 1. custom keys from config.h */ + /* 1. shortcuts */ + for(i = 0; i < LEN(shortcuts); i++) { + if((ksym == shortcuts[i].keysym) + && (CLEANMASK(shortcuts[i].mod) == \ + CLEANMASK(e->state)) + && shortcuts[i].func) { + shortcuts[i].func(&(shortcuts[i].arg)); + } + } + + /* 2. custom keys from config.h */ if((customkey = kmap(ksym, e->state))) { ttywrite(customkey, strlen(customkey)); /* 2. hardcoded (overrides X lookup) */ @@ -2616,14 +2705,15 @@ cmessage(XEvent *e) { } void -resize(XEvent *e) { +cresize(int width, int height) +{ int col, row; - if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h) - return; + if(width != 0) + xw.w = width; + if(height != 0) + xw.h = height; - xw.w = e->xconfigure.width; - xw.h = e->xconfigure.height; col = (xw.w - 2*BORDER) / xw.cw; row = (xw.h - 2*BORDER) / xw.ch; if(col == term.col && row == term.row) @@ -2635,6 +2725,14 @@ resize(XEvent *e) { } void +resize(XEvent *e) { + if(e->xconfigure.width == xw.w && e->xconfigure.height == xw.h) + return; + + cresize(e->xconfigure.width, e->xconfigure.height); +} + +void run(void) { XEvent ev; fd_set rfd; @@ -2748,8 +2846,8 @@ main(int argc, char *argv[]) { run: setlocale(LC_CTYPE, ""); tnew(80, 24); - ttynew(); xinit(); + ttynew(); selinit(); run(); return 0;