X-Git-Url: https://jasonwoof.com/gitweb/?p=st.git;a=blobdiff_plain;f=st.c;h=8059b1656c11587a12d412bea31462b33cba266f;hp=f967d2c0aba447bb88ae56a79258b8c0c44f64ce;hb=866590521609ba35606e53990e381bdc2adf742f;hpb=2e38ab7afdc56e3853751918f1b7705362bea01c diff --git a/st.c b/st.c index f967d2c..8059b16 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)) @@ -69,8 +72,6 @@ #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg) #define IS_SET(flag) (term.mode & (flag)) #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000) -#define X2COL(x) (((x) - BORDER)/xw.cw) -#define Y2ROW(y) (((y) - BORDER)/xw.ch) #define VT102ID "\033[?6c" @@ -95,8 +96,8 @@ enum cursor_movement { enum cursor_state { CURSOR_DEFAULT = 0, - CURSOR_HIDE = 1, - CURSOR_WRAPNEXT = 2 + CURSOR_WRAPNEXT = 1, + CURSOR_ORIGIN = 2 }; enum glyph_state { @@ -114,7 +115,8 @@ enum term_mode { MODE_MOUSEMOTION = 64, MODE_MOUSE = 32|64, MODE_REVERSE = 128, - MODE_KBDLOCK = 256 + MODE_KBDLOCK = 256, + MODE_HIDE = 512 }; enum escape_state { @@ -237,6 +239,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 */ @@ -281,6 +301,7 @@ 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 tnew(int, int); static void tnewline(int); static void tputtab(bool); @@ -320,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 *); @@ -340,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, @@ -379,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); @@ -407,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; @@ -581,6 +582,22 @@ selinit(void) { sel.xtarget = XA_STRING; } +static int +x2col(int x) { + x -= borderpx; + x /= xw.cw; + + return LIMIT(x, 0, term.col-1); +} + +static int +y2row(int y) { + y -= borderpx; + y /= xw.ch; + + return LIMIT(y, 0, term.row-1); +} + static inline bool selected(int x, int y) { int bx, ex; @@ -602,8 +619,9 @@ getbuttoninfo(XEvent *e, int *b, int *x, int *y) { if(b) *b = e->xbutton.button; - *x = X2COL(e->xbutton.x); - *y = Y2ROW(e->xbutton.y); + *x = x2col(e->xbutton.x); + *y = y2row(e->xbutton.y); + sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex; sel.b.y = MIN(sel.by, sel.ey); sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx; @@ -612,8 +630,8 @@ getbuttoninfo(XEvent *e, int *b, int *x, int *y) { void mousereport(XEvent *e) { - int x = X2COL(e->xbutton.x); - int y = Y2ROW(e->xbutton.y); + int x = x2col(e->xbutton.x); + int y = y2row(e->xbutton.y); int button = e->xbutton.button; int state = e->xbutton.state; char buf[] = { '\033', '[', 'M', 0, 32+x+1, 32+y+1 }; @@ -655,8 +673,12 @@ bpress(XEvent *e) { draw(); } sel.mode = 1; - sel.ex = sel.bx = X2COL(e->xbutton.x); - sel.ey = sel.by = Y2ROW(e->xbutton.y); + sel.ex = sel.bx = x2col(e->xbutton.x); + sel.ey = sel.by = y2row(e->xbutton.y); + } else if(e->xbutton.button == Button4) { + ttywrite("\031", 1); + } else if(e->xbutton.button == Button5) { + ttywrite("\005", 1); } } @@ -664,7 +686,7 @@ void selcopy(void) { char *str, *ptr, *p; int x, y, bufsize, is_selected = 0, size; - Glyph *gp; + Glyph *gp, *last; if(sel.bx == -1) { str = NULL; @@ -674,11 +696,16 @@ selcopy(void) { /* append every set & selected glyph to the selection */ for(y = 0; y < term.row; y++) { - for(x = 0; x < term.col; x++) { - gp = &term.line[y][x]; + gp = &term.line[y][0]; + last = gp + term.col; + + while(--last >= gp && !(last->state & GLYPH_SET)) + /* nothing */; + for(x = 0; gp <= last; x++, ++gp) { if(!(is_selected = selected(x, y))) continue; + p = (gp->state & GLYPH_SET) ? gp->c : " "; size = utf8size(p); memcpy(ptr, p, size); @@ -797,13 +824,13 @@ brelease(XEvent *e) { sel.bx = -1; gettimeofday(&now, NULL); - if(TIMEDIFF(now, sel.tclick2) <= TRIPLECLICK_TIMEOUT) { + if(TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) { /* triple click on the line */ sel.b.x = sel.bx = 0; sel.e.x = sel.ex = term.col; sel.b.y = sel.e.y = sel.ey; selcopy(); - } else if(TIMEDIFF(now, sel.tclick1) <= DOUBLECLICK_TIMEOUT) { + } else if(TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) { /* double click to select word */ sel.bx = sel.ex; while(sel.bx > 0 && term.line[sel.ey][sel.bx-1].state & GLYPH_SET && @@ -864,11 +891,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); @@ -876,8 +915,8 @@ execsh(void) { signal(SIGTERM, SIG_DFL); signal(SIGALRM, SIG_DFL); - DEFAULT(envshell, SHELL); - putenv("TERM="TNAME); + DEFAULT(envshell, shell); + setenv("TERM", termname, 1); args = opt_cmd ? opt_cmd : (char *[]){envshell, "-i", NULL}; execvp(args[0], args); exit(EXIT_FAILURE); @@ -926,13 +965,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)); } } } @@ -1028,18 +1066,20 @@ treset(void) { term.c = (TCursor){{ .mode = ATTR_NULL, - .fg = DefaultFG, - .bg = DefaultBG + .fg = defaultfg, + .bg = defaultbg }, .x = 0, .y = 0, .state = CURSOR_DEFAULT}; memset(term.tabs, 0, term.col * sizeof(*term.tabs)); - for(i = TAB; i < term.col; i += TAB) + for(i = tabspaces; i < term.col; i += tabspaces) term.tabs[i] = 1; term.top = 0; term.bot = term.row - 1; term.mode = MODE_WRAP; tclearregion(0, 0, term.col-1, term.row-1); + tmoveto(0, 0); + tcursor(CURSOR_SAVE); } void @@ -1173,10 +1213,25 @@ csiparse(void) { } } +/* for absolute user moves, when decom is set */ +void +tmoveato(int x, int y) { + tmoveto(x, y + ((term.c.state & CURSOR_ORIGIN) ? term.top: 0)); +} + void tmoveto(int x, int y) { + int miny, maxy; + + if(term.c.state & CURSOR_ORIGIN) { + miny = term.top; + maxy = term.bot; + } else { + miny = 0; + maxy = term.row - 1; + } LIMIT(x, 0, term.col-1); - LIMIT(y, 0, term.row-1); + LIMIT(y, miny, maxy); term.c.state &= ~CURSOR_WRAPNEXT; term.c.x = x; term.c.y = y; @@ -1293,8 +1348,8 @@ tsetattr(int *attr, int l) { case 0: term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE | ATTR_BOLD \ | ATTR_ITALIC | ATTR_BLINK); - term.c.attr.fg = DefaultFG; - term.c.attr.bg = DefaultBG; + term.c.attr.fg = defaultfg; + term.c.attr.bg = defaultbg; break; case 1: term.c.attr.mode |= ATTR_BOLD; @@ -1344,7 +1399,7 @@ tsetattr(int *attr, int l) { } break; case 39: - term.c.attr.fg = DefaultFG; + term.c.attr.fg = defaultfg; break; case 48: if(i + 2 < l && attr[i + 1] == 5) { @@ -1363,7 +1418,7 @@ tsetattr(int *attr, int l) { } break; case 49: - term.c.attr.bg = DefaultBG; + term.c.attr.bg = defaultbg; break; default: if(BETWEEN(attr[i], 30, 37)) { @@ -1418,18 +1473,25 @@ tsetmode(bool priv, bool set, int *args, int narg) { if(mode != term.mode) redraw(); break; - case 6: /* XXX: DECOM -- Origin */ + case 6: /* DECOM -- Origin */ + MODBIT(term.c.state, set, CURSOR_ORIGIN); + tmoveato(0, 0); break; case 7: /* DECAWM -- Auto wrap */ MODBIT(term.mode, set, MODE_WRAP); break; - case 8: /* XXX: DECARM -- Auto repeat */ - break; case 0: /* Error (IGNORED) */ + case 2: /* DECANM -- ANSI/VT52 (IGNORED) */ + case 3: /* DECCOLM -- Column (IGNORED) */ + case 4: /* DECSCLM -- Scroll (IGNORED) */ + case 8: /* DECARM -- Auto repeat (IGNORED) */ + case 18: /* DECPFF -- Printer feed (IGNORED) */ + case 19: /* DECPEX -- Printer extent (IGNORED) */ + case 42: /* DECNRCM -- National characters (IGNORED) */ case 12: /* att610 -- Start blinking cursor (IGNORED) */ break; - case 25: - MODBIT(term.c.state, !set, CURSOR_HIDE); + case 25: /* DECTCEM -- Text Cursor Enable Mode */ + MODBIT(term.mode, !set, MODE_HIDE); break; case 1000: /* 1000,1002: enable xterm mouse report */ MODBIT(term.mode, set, MODE_MOUSEBTN); @@ -1439,26 +1501,20 @@ tsetmode(bool priv, bool set, int *args, int narg) { break; case 1049: /* = 1047 and 1048 */ case 47: - case 1047: - if(IS_SET(MODE_ALTSCREEN)) + case 1047: { + bool alt = IS_SET(MODE_ALTSCREEN) != 0; + if(alt) tclearregion(0, 0, term.col-1, term.row-1); - if((set && !IS_SET(MODE_ALTSCREEN)) || - (!set && IS_SET(MODE_ALTSCREEN))) { + if(set ^ alt) /* set is always 1 or 0 */ tswapscreen(); - } if(*args != 1049) break; + } /* pass through */ case 1048: tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); break; default: - /* case 2: DECANM -- ANSI/VT52 (NOT SUPPOURTED) */ - /* case 3: DECCOLM -- Column (NOT SUPPORTED) */ - /* case 4: DECSCLM -- Scroll (NOT SUPPORTED) */ - /* case 18: DECPFF -- Printer feed (NOT SUPPORTED) */ - /* case 19: DECPEX -- Printer extent (NOT SUPPORTED) */ - /* case 42: DECNRCM -- National characters (NOT SUPPORTED) */ fprintf(stderr, "erresc: unknown private set/reset mode %d\n", *args); @@ -1505,11 +1561,11 @@ csihandle(void) { tinsertblank(csiescseq.arg[0]); break; case 'A': /* CUU -- Cursor Up */ - case 'e': DEFAULT(csiescseq.arg[0], 1); tmoveto(term.c.x, term.c.y-csiescseq.arg[0]); break; case 'B': /* CUD -- Cursor Down */ + case 'e': /* VPR --Cursor Down */ DEFAULT(csiescseq.arg[0], 1); tmoveto(term.c.x, term.c.y+csiescseq.arg[0]); break; @@ -1518,7 +1574,7 @@ csihandle(void) { ttywrite(VT102ID, sizeof(VT102ID) - 1); break; case 'C': /* CUF -- Cursor Forward */ - case 'a': + case 'a': /* HPR -- Cursor Forward */ DEFAULT(csiescseq.arg[0], 1); tmoveto(term.c.x+csiescseq.arg[0], term.c.y); break; @@ -1555,7 +1611,7 @@ csihandle(void) { case 'f': /* HVP */ DEFAULT(csiescseq.arg[0], 1); DEFAULT(csiescseq.arg[1], 1); - tmoveto(csiescseq.arg[1]-1, csiescseq.arg[0]-1); + tmoveato(csiescseq.arg[1]-1, csiescseq.arg[0]-1); break; case 'I': /* CHT -- Cursor Forward Tabulation tab stops */ DEFAULT(csiescseq.arg[0], 1); @@ -1629,7 +1685,7 @@ csihandle(void) { break; case 'd': /* VPA -- Move to */ DEFAULT(csiescseq.arg[0], 1); - tmoveto(term.c.x, csiescseq.arg[0]-1); + tmoveato(term.c.x, csiescseq.arg[0]-1); break; case 'h': /* SM -- Set terminal mode */ tsetmode(csiescseq.priv, 1, csiescseq.arg, csiescseq.narg); @@ -1644,7 +1700,7 @@ csihandle(void) { DEFAULT(csiescseq.arg[0], 1); DEFAULT(csiescseq.arg[1], term.row); tsetscroll(csiescseq.arg[0]-1, csiescseq.arg[1]-1); - tmoveto(0, 0); + tmoveato(0, 0); } break; case 's': /* DECSC -- Save cursor position (ANSI.SYS) */ @@ -1793,11 +1849,17 @@ 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 + * STR sequences must be checked before anything else + * because it can use some control codes as part of the sequence. */ if(term.esc & ESC_STR) { switch(ascii) { @@ -1817,6 +1879,7 @@ tputc(char *c, int len) { } return; } + /* * Actions of control codes must be performed as soon they arrive * because they can be embedded inside a control sequence, and @@ -1857,11 +1920,11 @@ tputc(char *c, int len) { case '\030': /* CAN */ csireset(); return; - case '\005': /* ENQ (IGNORED) */ - case '\000': /* NUL (IGNORED) */ - case '\021': /* XON (IGNORED) */ - case '\023': /* XOFF (IGNORED) */ - case 0177: /* DEL (IGNORED) */ + case '\005': /* ENQ (IGNORED) */ + case '\000': /* NUL (IGNORED) */ + case '\021': /* XON (IGNORED) */ + case '\023': /* XOFF (IGNORED) */ + case 0177: /* DEL (IGNORED) */ return; } } else if(term.esc & ESC_START) { @@ -2068,23 +2131,24 @@ tresize(int col, int row) { memset(bp, 0, sizeof(*term.tabs) * (col - term.col)); while(--bp > term.tabs && !*bp) /* nothing */ ; - for(bp += TAB; bp < term.tabs + col; bp += TAB) + for(bp += tabspaces; bp < term.tabs + col; bp += tabspaces) *bp = 1; } /* update terminal size */ - term.col = col, term.row = row; - /* make use of the LIMIT in tmoveto */ - tmoveto(term.c.x, term.c.y); + term.col = col; + term.row = row; /* reset scrolling region */ tsetscroll(0, row-1); + /* make use of the LIMIT in tmoveto */ + tmoveto(term.c.x, term.c.y); return (slide > 0); } void xresize(int col, int row) { - xw.tw = MAX(1, 2*BORDER + col * xw.cw); - xw.th = MAX(1, 2*BORDER + row * xw.ch); + xw.tw = MAX(1, 2*borderpx + col * xw.cw); + xw.th = MAX(1, 2*borderpx + row * xw.ch); XftDrawChange(xw.xft_draw, xw.buf); } @@ -2130,9 +2194,9 @@ xloadcols(void) { void xtermclear(int col1, int row1, int col2, int row2) { XftDrawRect(xw.xft_draw, - &dc.xft_col[IS_SET(MODE_REVERSE) ? DefaultFG : DefaultBG], - BORDER + col1 * xw.cw, - BORDER + row1 * xw.ch, + &dc.xft_col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg], + borderpx + col1 * xw.cw, + borderpx + row1 * xw.ch, (col2-col1+1) * xw.cw, (row2-row1+1) * xw.ch); } @@ -2143,13 +2207,13 @@ xtermclear(int col1, int row1, int col2, int row2) { void xclear(int x1, int y1, int x2, int y2) { XftDrawRect(xw.xft_draw, - &dc.xft_col[IS_SET(MODE_REVERSE) ? DefaultFG : DefaultBG], + &dc.xft_col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg], x1, y1, x2-x1, y2-y1); } void xhints(void) { - XClassHint class = {opt_class ? opt_class : TNAME, TNAME}; + XClassHint class = {opt_class ? opt_class : termname, termname}; XWMHints wm = {.flags = InputHint, .input = 1}; XSizeHints *sizeh = NULL; @@ -2160,8 +2224,8 @@ xhints(void) { sizeh->width = xw.w; sizeh->height_inc = xw.ch; sizeh->width_inc = xw.cw; - sizeh->base_height = 2*BORDER; - sizeh->base_width = 2*BORDER; + sizeh->base_height = 2*borderpx; + sizeh->base_width = 2*borderpx; } else { sizeh->flags = PMaxSize | PMinSize; sizeh->min_width = sizeh->max_width = xw.fw; @@ -2172,22 +2236,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; @@ -2197,27 +2256,73 @@ 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; + + if(fontstr[0] == '-') { + pattern = XftXlfdParse(fontstr, False, False); + } else { + 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); + + 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); + + FcPatternDel(pattern, FC_WEIGHT); + if(xloadfont(&dc.ifont, pattern)) + die("st: can't open font %s\n", fontstr); - fstr = smstrcat(fontstr, ":slant=italic,oblique", NULL); - xinitfont(&dc.ifont, fstr); - free(fstr); + FcPatternDestroy(pattern); +} - fstr = smstrcat(fontstr, ":weight=bold:slant=italic,oblique", NULL); - xinitfont(&dc.ibfont, fstr); - free(fstr); +void +xzoom(const Arg *arg) +{ + xloadfonts(usedfont, usedfontsize + arg->i); + cresize(0, 0); + draw(); } void @@ -2233,7 +2338,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); @@ -2252,14 +2358,14 @@ xinit(void) { xw.w = xw.fw; } else { /* window - default size */ - xw.h = 2*BORDER + term.row * xw.ch; - xw.w = 2*BORDER + term.col * xw.cw; + xw.h = 2*borderpx + term.row * xw.ch; + xw.w = 2*borderpx + term.col * xw.cw; xw.fx = 0; xw.fy = 0; } - attrs.background_pixel = dc.xft_col[DefaultBG].pixel; - attrs.border_pixel = dc.xft_col[DefaultBG].pixel; + attrs.background_pixel = dc.xft_col[defaultbg].pixel; + attrs.border_pixel = dc.xft_col[defaultbg].pixel; attrs.bit_gravity = NorthWestGravity; attrs.event_mask = FocusChangeMask | KeyPressMask | ExposureMask | VisibilityChangeMask | StructureNotifyMask @@ -2309,7 +2415,7 @@ xinit(void) { void xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { - int winx = BORDER + x * xw.cw, winy = BORDER + y * xw.ch, + int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, width = charlen * xw.cw; Font *font = &dc.font; XGlyphInfo extents; @@ -2317,9 +2423,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { *temp, revfg, revbg; XRenderColor colfg, colbg; - if(base.mode & ATTR_REVERSE) - temp = fg, fg = bg, bg = temp; - if(base.mode & ATTR_BOLD) { if(BETWEEN(base.fg, 0, 7)) { /* basic system colors */ @@ -2342,12 +2445,12 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { if(base.mode & ATTR_ITALIC) font = &dc.ifont; - if(base.mode & (ATTR_ITALIC|ATTR_ITALIC)) + if((base.mode & ATTR_ITALIC) && (base.mode & ATTR_BOLD)) font = &dc.ibfont; if(IS_SET(MODE_REVERSE)) { - if(fg == &dc.xft_col[DefaultFG]) { - fg = &dc.xft_col[DefaultBG]; + if(fg == &dc.xft_col[defaultfg]) { + fg = &dc.xft_col[defaultbg]; } else { colfg.red = ~fg->color.red; colfg.green = ~fg->color.green; @@ -2357,8 +2460,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { fg = &revfg; } - if(bg == &dc.xft_col[DefaultBG]) { - bg = &dc.xft_col[DefaultFG]; + if(bg == &dc.xft_col[defaultbg]) { + bg = &dc.xft_col[defaultfg]; } else { colbg.red = ~bg->color.red; colbg.green = ~bg->color.green; @@ -2369,13 +2472,16 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { } } + if(base.mode & ATTR_REVERSE) + temp = fg, fg = bg, bg = temp; + XftTextExtentsUtf8(xw.dpy, font->xft_set, (FcChar8 *)s, bytelen, &extents); width = extents.xOff; /* Intelligent cleaning up of the borders. */ if(x == 0) { - xclear(0, (y == 0)? 0 : winy, BORDER, + xclear(0, (y == 0)? 0 : winy, borderpx, winy + xw.ch + (y == term.row-1)? xw.h : 0); } if(x + charlen >= term.col-1) { @@ -2383,7 +2489,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { (y == term.row-1)? xw.h : (winy + xw.ch)); } if(y == 0) - xclear(winx, 0, winx + width, BORDER); + xclear(winx, 0, winx + width, borderpx); if(y == term.row-1) xclear(winx, winy + xw.ch, winx + width, xw.h); @@ -2401,7 +2507,7 @@ void xdrawcursor(void) { static int oldx = 0, oldy = 0; int sl; - Glyph g = {{' '}, ATTR_NULL, DefaultBG, DefaultCS, 0}; + Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs, 0}; LIMIT(oldx, 0, term.col-1); LIMIT(oldy, 0, term.row-1); @@ -2419,12 +2525,12 @@ xdrawcursor(void) { } /* draw the new one */ - if(!(term.c.state & CURSOR_HIDE)) { + if(!(IS_SET(MODE_HIDE))) { if(!(xw.state & WIN_FOCUSED)) - g.bg = DefaultUCS; + g.bg = defaultucs; if(IS_SET(MODE_REVERSE)) - g.mode |= ATTR_REVERSE, g.fg = DefaultCS, g.bg = DefaultFG; + g.mode |= ATTR_REVERSE, g.fg = defaultcs, g.bg = defaultfg; sl = utf8size(g.c); xdraws(g.c, g, term.c.x, term.c.y, 1, sl); @@ -2460,9 +2566,9 @@ drawregion(int x1, int y1, int x2, int y2) { int ic, ib, x, y, ox, sl; Glyph base, new; char buf[DRAW_BUF_SIZ]; - bool ena_sel = sel.bx != -1, alt = IS_SET(MODE_ALTSCREEN); + bool ena_sel = sel.bx != -1, alt = IS_SET(MODE_ALTSCREEN) != 0; - if((sel.alt && !alt) || (!sel.alt && alt)) + if((sel.alt != 0) ^ alt) ena_sel = 0; if(!(xw.state & WIN_VISIBLE)) return; @@ -2541,9 +2647,11 @@ xseturgency(int add) { void focus(XEvent *ev) { if(ev->type == FocusIn) { + XSetICFocus(xw.xic); xw.state |= WIN_FOCUSED; xseturgency(0); } else { + XUnsetICFocus(xw.xic); xw.state &= ~WIN_FOCUSED; } } @@ -2569,11 +2677,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)) @@ -2583,7 +2688,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) */ @@ -2604,6 +2719,9 @@ kpress(XEvent *ev) { selpaste(); break; case XK_Return: + if(meta) + ttywrite("\033", 1); + if(IS_SET(MODE_CRLF)) { ttywrite("\r\n", 2); } else { @@ -2641,18 +2759,17 @@ 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) - return; + col = (xw.w - 2*borderpx) / xw.cw; + row = (xw.h - 2*borderpx) / xw.ch; tresize(col, row); xresize(col, row); @@ -2660,6 +2777,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; @@ -2697,7 +2822,7 @@ run(void) { while(XPending(xw.dpy)) { XNextEvent(xw.dpy, &ev); - if(XFilterEvent(&ev, xw.win)) + if(XFilterEvent(&ev, None)) continue; if(handler[ev.type]) (handler[ev.type])(&ev); @@ -2772,9 +2897,10 @@ main(int argc, char *argv[]) { run: setlocale(LC_CTYPE, ""); + XSetLocaleModifiers(""); tnew(80, 24); - ttynew(); xinit(); + ttynew(); selinit(); run(); return 0;