X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=st.c;h=42061b9809a3e4221fb6ac9564cf35057e6d4d60;hb=2696f8187509eb94644bbac5b05348e37c391bea;hp=8ef1346b64aeaf96d4c377c291f290ee0074eab7;hpb=091ae143ce09e930fd61dae15f8d613c7eab5a61;p=st.git diff --git a/st.c b/st.c index 8ef1346..42061b9 100644 --- a/st.c +++ b/st.c @@ -28,8 +28,12 @@ #include #include #include + #define Glyph Glyph_ #define Font Font_ +#define Draw XftDraw * +#define Colour XftColor +#define Colourmap Colormap #if defined(__linux) #include @@ -55,13 +59,12 @@ #define STR_ARG_SIZ 16 #define DRAW_BUF_SIZ 20*1024 #define UTF_SIZ 4 -#define XK_NO_MOD UINT_MAX -#define XK_ANY_MOD 0 +#define XK_ANY_MOD UINT_MAX +#define XK_NO_MOD 0 #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)) @@ -70,10 +73,8 @@ #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg) -#define IS_SET(flag) (term.mode & (flag)) +#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 X2COL(x) (((x) - borderpx)/xw.cw) -#define Y2ROW(y) (((y) - borderpx)/xw.ch) #define VT102ID "\033[?6c" @@ -88,18 +89,14 @@ enum glyph_attribute { }; enum cursor_movement { - CURSOR_UP, - CURSOR_DOWN, - CURSOR_LEFT, - CURSOR_RIGHT, CURSOR_SAVE, CURSOR_LOAD }; enum cursor_state { CURSOR_DEFAULT = 0, - CURSOR_HIDE = 1, - CURSOR_WRAPNEXT = 2 + CURSOR_WRAPNEXT = 1, + CURSOR_ORIGIN = 2 }; enum glyph_state { @@ -108,16 +105,19 @@ enum glyph_state { }; enum term_mode { - MODE_WRAP = 1, + MODE_WRAP = 1, MODE_INSERT = 2, MODE_APPKEYPAD = 4, MODE_ALTSCREEN = 8, - MODE_CRLF = 16, + MODE_CRLF = 16, MODE_MOUSEBTN = 32, MODE_MOUSEMOTION = 64, MODE_MOUSE = 32|64, MODE_REVERSE = 128, - MODE_KBDLOCK = 256 + MODE_KBDLOCK = 256, + MODE_HIDE = 512, + MODE_ECHO = 1024, + MODE_APPCURSOR = 2048 }; enum escape_state { @@ -194,19 +194,20 @@ typedef struct { int bot; /* bottom scroll limit */ int mode; /* terminal mode flags */ int esc; /* escape state flags */ + bool numlock; /* lock numbers in keyboard */ bool *tabs; } Term; /* Purely graphic info */ typedef struct { - Display* dpy; - Colormap cmap; + Display *dpy; + Colourmap cmap; Window win; XdbeBackBuffer buf; Atom xembed, wmdeletewin; XIM xim; XIC xic; - XftDraw *xft_draw; + Draw draw; Visual *vis; int scr; bool isfixed; /* is fixed geometry? */ @@ -223,6 +224,10 @@ typedef struct { KeySym k; uint mask; char s[ESC_BUF_SIZ]; + /* three valued logic variables: 0 indifferent, 1 on, -1 off */ + signed char appkey; /* application keypad */ + signed char appcursor; /* application cursor */ + signed char crlf; /* crlf mode */ } Key; /* TODO: use better name for vars... */ @@ -256,6 +261,8 @@ typedef struct { /* function definitions used in config.h */ static void xzoom(const Arg *); +static void selpaste(const Arg *); +static void numlock(const Arg *); /* Config.h for applying patches and the configuration. */ #include "config.h" @@ -268,13 +275,12 @@ typedef struct { int descent; short lbearing; short rbearing; - XftFont *xft_set; + XftFont *set; } Font; /* Drawing Context */ typedef struct { - XftColor xft_col[LEN(colorname) < 256 ? 256 : LEN(colorname)]; - GC gc; + Colour col[LEN(colorname) < 256 ? 256 : LEN(colorname)]; Font font, bfont, ifont, ibfont; } DC; @@ -302,6 +308,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); @@ -317,7 +324,9 @@ static void tswapscreen(void); static void tsetdirt(int, int); static void tsetmode(bool, bool, int *, int); static void tfulldirt(void); +static void techo(char *, int); +static inline bool match(uint, uint); static void ttynew(void); static void ttyread(void); static void ttyresize(void); @@ -354,7 +363,6 @@ static void selrequest(XEvent *); static void selinit(void); static inline bool selected(int, int); static void selcopy(void); -static void selpaste(void); static void selscroll(int, int); static int utf8decode(char *, long *); @@ -582,6 +590,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; @@ -599,12 +623,12 @@ selected(int x, int y) { } void -getbuttoninfo(XEvent *e, int *b, int *x, int *y) { - if(b) - *b = e->xbutton.button; +getbuttoninfo(XEvent *e) { + sel.alt = IS_SET(MODE_ALTSCREEN); + + sel.ex = x2col(e->xbutton.x); + sel.ey = 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; @@ -613,8 +637,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 }; @@ -656,8 +680,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); } } @@ -696,7 +724,6 @@ selcopy(void) { } *ptr = 0; } - sel.alt = IS_SET(MODE_ALTSCREEN); xsetsel(str); } @@ -723,7 +750,7 @@ selnotify(XEvent *e) { } void -selpaste(void) { +selpaste(const Arg *dummy) { XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY, xw.win, CurrentTime); } @@ -794,10 +821,10 @@ brelease(XEvent *e) { } if(e->xbutton.button == Button2) { - selpaste(); + selpaste(NULL); } else if(e->xbutton.button == Button1) { sel.mode = 0; - getbuttoninfo(e, NULL, &sel.ex, &sel.ey); + getbuttoninfo(e); term.dirty[sel.ey] = 1; if(sel.bx == sel.ex && sel.by == sel.ey) { sel.bx = -1; @@ -843,16 +870,17 @@ bmotion(XEvent *e) { return; } - if(sel.mode) { - oldey = sel.ey; - oldex = sel.ex; - getbuttoninfo(e, NULL, &sel.ex, &sel.ey); + if(!sel.mode) + return; - if(oldey != sel.ey || oldex != sel.ex) { - starty = MIN(oldey, sel.ey); - endy = MAX(oldey, sel.ey); - tsetdirt(starty, endy); - } + oldey = sel.ey; + oldex = sel.ex; + getbuttoninfo(e); + + if(oldey != sel.ey || oldex != sel.ex) { + starty = MIN(oldey, sel.ey); + endy = MAX(oldey, sel.ey); + tsetdirt(starty, endy); } } @@ -1057,6 +1085,8 @@ treset(void) { term.mode = MODE_WRAP; tclearregion(0, 0, term.col-1, term.row-1); + tmoveto(0, 0); + tcursor(CURSOR_SAVE); } void @@ -1074,6 +1104,8 @@ tnew(int col, int row) { term.alt [row] = xmalloc(term.col * sizeof(Glyph)); term.dirty[row] = 0; } + + term.numlock = 1; memset(term.tabs, 0, term.col * sizeof(*term.tabs)); /* setup screen */ treset(); @@ -1190,10 +1222,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; @@ -1421,13 +1468,14 @@ tsetscroll(int t, int b) { void tsetmode(bool priv, bool set, int *args, int narg) { int *lim, mode; + bool alt; for(lim = args + narg; args < lim; ++args) { if(priv) { switch(*args) { break; case 1: /* DECCKM -- Cursor key */ - MODBIT(term.mode, set, MODE_APPKEYPAD); + MODBIT(term.mode, set, MODE_APPCURSOR); break; case 5: /* DECSCNM -- Reverse video */ mode = term.mode; @@ -1435,18 +1483,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); @@ -1456,26 +1511,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: { + alt = IS_SET(MODE_ALTSCREEN); + 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); @@ -1491,7 +1540,8 @@ tsetmode(bool priv, bool set, int *args, int narg) { case 4: /* IRM -- Insertion-replacement */ MODBIT(term.mode, set, MODE_INSERT); break; - case 12: /* XXX: SRM -- Send/Receive */ + case 12: /* SRM -- Send/Receive */ + MODBIT(term.mode, !set, MODE_ECHO); break; case 20: /* LNM -- Linefeed/new line */ MODBIT(term.mode, set, MODE_CRLF); @@ -1522,11 +1572,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; @@ -1535,7 +1585,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; @@ -1572,7 +1622,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); @@ -1646,7 +1696,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); @@ -1661,7 +1711,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) */ @@ -1806,6 +1856,28 @@ tputtab(bool forward) { } void +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 != '\n' && c != '\r' && c != '\t') { + c |= '\x40'; + tputc("^", 1); + } + tputc(&c, 1); + } else { + break; + } + } + if (len) + tputc(buf, len); +} + +void tputc(char *c, int len) { uchar ascii = *c; bool control = ascii < '\x20' || ascii == 0177; @@ -1819,8 +1891,8 @@ tputc(char *c, int len) { } } /* - * 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) { @@ -1840,6 +1912,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 @@ -1880,11 +1953,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) { @@ -2012,7 +2085,7 @@ tputc(char *c, int len) { } } /* - * All characters which forms part of a sequence are not + * All characters which form part of a sequence are not * printed */ return; @@ -2026,11 +2099,19 @@ 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 */ + + if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col) { + memmove(&term.line[term.c.y][term.c.x+1], + &term.line[term.c.y][term.c.x], + (term.col - term.c.x - 1) * sizeof(Glyph)); + } + tsetchar(c, &term.c.attr, term.c.x, term.c.y); - if(term.c.x+1 < term.col) + if(term.c.x+1 < term.col) { tmoveto(term.c.x+1, term.c.y); - else + } else { term.c.state |= CURSOR_WRAPNEXT; + } } int @@ -2097,32 +2178,32 @@ tresize(int col, int row) { /* update terminal size */ term.col = col; term.row = row; - /* make use of the LIMIT in tmoveto */ - tmoveto(term.c.x, term.c.y); /* 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*borderpx + col * xw.cw); - xw.th = MAX(1, 2*borderpx + row * xw.ch); + xw.tw = MAX(1, col * xw.cw); + xw.th = MAX(1, row * xw.ch); - XftDrawChange(xw.xft_draw, xw.buf); + XftDrawChange(xw.draw, xw.buf); } void xloadcols(void) { int i, r, g, b; - XRenderColor xft_color = { .alpha = 0 }; + XRenderColor color = { .alpha = 0 }; /* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */ for(i = 0; i < LEN(colorname); i++) { if(!colorname[i]) continue; - if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[i], &dc.xft_col[i])) { + if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[i], &dc.col[i])) { die("Could not allocate color '%s'\n", colorname[i]); } } @@ -2131,10 +2212,10 @@ xloadcols(void) { for(i = 16, r = 0; r < 6; r++) { for(g = 0; g < 6; g++) { for(b = 0; b < 6; b++) { - xft_color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r; - xft_color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g; - xft_color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b; - if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color, &dc.xft_col[i])) { + color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r; + color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g; + color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b; + if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i])) { die("Could not allocate color %d\n", i); } i++; @@ -2143,9 +2224,9 @@ xloadcols(void) { } for(r = 0; r < 24; r++, i++) { - xft_color.red = xft_color.green = xft_color.blue = 0x0808 + 0x0a0a * r; - if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &xft_color, - &dc.xft_col[i])) { + color.red = color.green = color.blue = 0x0808 + 0x0a0a * r; + if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, + &dc.col[i])) { die("Could not allocate color %d\n", i); } } @@ -2153,8 +2234,8 @@ 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], + XftDrawRect(xw.draw, + &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg], borderpx + col1 * xw.cw, borderpx + row1 * xw.ch, (col2-col1+1) * xw.cw, @@ -2166,8 +2247,8 @@ 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], + XftDrawRect(xw.draw, + &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg], x1, y1, x2-x1, y2-y1); } @@ -2184,8 +2265,8 @@ xhints(void) { sizeh->width = xw.w; sizeh->height_inc = xw.ch; sizeh->width_inc = xw.cw; - sizeh->base_height = 2*borderpx; - sizeh->base_width = 2*borderpx; + sizeh->base_height = 2 * borderpx; + sizeh->base_width = 2 * borderpx; } else { sizeh->flags = PMaxSize | PMinSize; sizeh->min_width = sizeh->max_width = xw.fw; @@ -2204,17 +2285,17 @@ xloadfont(Font *f, FcPattern *pattern) { match = XftFontMatch(xw.dpy, xw.scr, pattern, &result); if(!match) return 1; - if(!(f->xft_set = XftFontOpenPattern(xw.dpy, match))) { + if(!(f->set = XftFontOpenPattern(xw.dpy, match))) { FcPatternDestroy(match); return 1; } - f->ascent = f->xft_set->ascent; - f->descent = f->xft_set->descent; + f->ascent = f->set->ascent; + f->descent = f->set->descent; f->lbearing = 0; - f->rbearing = f->xft_set->max_advance_width; + f->rbearing = f->set->max_advance_width; - f->height = f->xft_set->height; + f->height = f->set->height; f->width = f->lbearing + f->rbearing; return 0; @@ -2318,14 +2399,14 @@ xinit(void) { 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.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.col[defaultbg].pixel; + attrs.border_pixel = dc.col[defaultbg].pixel; attrs.bit_gravity = NorthWestGravity; attrs.event_mask = FocusChangeMask | KeyPressMask | ExposureMask | VisibilityChangeMask | StructureNotifyMask @@ -2346,15 +2427,13 @@ xinit(void) { xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeCopied); /* Xft rendering context */ - xw.xft_draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); + xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); /* input methods */ xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL); xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL); - /* gc */ - dc.gc = XCreateGC(xw.dpy, xw.win, 0, NULL); /* white cursor, black outline */ cursor = XCreateFontCursor(xw.dpy, XC_xterm); @@ -2379,23 +2458,20 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { width = charlen * xw.cw; Font *font = &dc.font; XGlyphInfo extents; - XftColor *fg = &dc.xft_col[base.fg], *bg = &dc.xft_col[base.bg], + Colour *fg = &dc.col[base.fg], *bg = &dc.col[base.bg], *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 */ - fg = &dc.xft_col[base.fg + 8]; + fg = &dc.col[base.fg + 8]; } else if(BETWEEN(base.fg, 16, 195)) { /* 256 colors */ - fg = &dc.xft_col[base.fg + 36]; + fg = &dc.col[base.fg + 36]; } else if(BETWEEN(base.fg, 232, 251)) { /* greyscale */ - fg = &dc.xft_col[base.fg + 4]; + fg = &dc.col[base.fg + 4]; } /* * Those ranges will not be brightened: @@ -2408,12 +2484,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_BOLD)) + 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.col[defaultfg]) { + fg = &dc.col[defaultbg]; } else { colfg.red = ~fg->color.red; colfg.green = ~fg->color.green; @@ -2423,8 +2499,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.col[defaultbg]) { + bg = &dc.col[defaultfg]; } else { colbg.red = ~bg->color.red; colbg.green = ~bg->color.green; @@ -2435,7 +2511,10 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { } } - XftTextExtentsUtf8(xw.dpy, font->xft_set, (FcChar8 *)s, bytelen, + if(base.mode & ATTR_REVERSE) + temp = fg, fg = bg, bg = temp; + + XftTextExtentsUtf8(xw.dpy, font->set, (FcChar8 *)s, bytelen, &extents); width = extents.xOff; @@ -2453,12 +2532,12 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { if(y == term.row-1) xclear(winx, winy + xw.ch, winx + width, xw.h); - XftDrawRect(xw.xft_draw, bg, winx, winy, width, xw.ch); - XftDrawStringUtf8(xw.xft_draw, fg, font->xft_set, winx, + XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch); + XftDrawStringUtf8(xw.draw, fg, font->set, winx, winy + font->ascent, (FcChar8 *)s, bytelen); if(base.mode & ATTR_UNDERLINE) { - XftDrawRect(xw.xft_draw, fg, winx, winy + font->ascent + 1, + XftDrawRect(xw.draw, fg, winx, winy + font->ascent + 1, width, 1); } } @@ -2485,7 +2564,7 @@ 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; @@ -2526,10 +2605,11 @@ 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; - if((sel.alt && !alt) || (!sel.alt && alt)) + if(sel.alt ^ IS_SET(MODE_ALTSCREEN)) ena_sel = 0; + if(!(xw.state & WIN_VISIBLE)) return; @@ -2616,20 +2696,70 @@ focus(XEvent *ev) { } } +inline bool +match(uint mask, uint state) { + if(mask == XK_NO_MOD && state) + return false; + if(mask != XK_ANY_MOD && mask != XK_NO_MOD && !state) + return false; + if((state & mask) != state) + return false; + return true; +} + +void +numlock(const Arg *dummy) { + term.numlock ^= 1; +} + char* kmap(KeySym k, uint state) { - int i; uint mask; + Key *kp; + int i; + + /* Check for mapped keys out of X11 function keys. */ + for(i = 0; i < LEN(mappedkeys); i++) { + if(mappedkeys[i] == k) + break; + } + if(i == LEN(mappedkeys)) { + if((k & 0xFFFF) < 0xFF00) + return NULL; + } + + for(kp = key; kp < key + LEN(key); kp++) { + mask = kp->mask; + + if(kp->k != k) + continue; + + if(!match(mask, state)) + continue; - state &= ~Mod2Mask; - for(i = 0; i < LEN(key); i++) { - mask = key[i].mask; + 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)) { + continue; + } - if(key[i].k == k && ((state & mask) == mask - || (mask == XK_NO_MOD && !state))) { - return (char*)key[i].s; + if((kp->appcursor < 0 && IS_SET(MODE_APPCURSOR)) || + (kp->appcursor > 0 + && !IS_SET(MODE_APPCURSOR))) { + continue; } + + if((kp->crlf < 0 && IS_SET(MODE_CRLF)) || + (kp->crlf > 0 && !IS_SET(MODE_CRLF))) { + continue; + } + + return kp->s; } + return NULL; } @@ -2637,66 +2767,46 @@ void kpress(XEvent *ev) { XKeyEvent *e = &ev->xkey; KeySym ksym; - char buf[32], *customkey; - int len, meta, shift, i; + char xstr[31], buf[32], *customkey, *cp = buf; + int len; Status status; + Shortcut *bp; if (IS_SET(MODE_KBDLOCK)) return; - meta = e->state & Mod1Mask; - shift = e->state & ShiftMask; - len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status); - + len = XmbLookupString(xw.xic, e, xstr, sizeof(xstr), &ksym, &status); + e->state &= ~Mod2Mask; /* 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)); + for(bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { + if(ksym == bp->keysym && match(bp->mod, e->state)) { + bp->func(&(bp->arg)); + return; } } /* 2. custom keys from config.h */ if((customkey = kmap(ksym, e->state))) { - ttywrite(customkey, strlen(customkey)); + len = strlen(customkey); + memcpy(buf, customkey, len); /* 2. hardcoded (overrides X lookup) */ } else { - switch(ksym) { - case XK_Up: - case XK_Down: - case XK_Left: - case XK_Right: - /* XXX: shift up/down doesn't work */ - sprintf(buf, "\033%c%c", - IS_SET(MODE_APPKEYPAD) ? 'O' : '[', - (shift ? "dacb":"DACB")[ksym - XK_Left]); - ttywrite(buf, 3); - break; - case XK_Insert: - if(shift) - selpaste(); - break; - case XK_Return: - if(IS_SET(MODE_CRLF)) { - ttywrite("\r\n", 2); - } else { - ttywrite("\r", 1); - } - break; - /* 3. X lookup */ - default: - if(len > 0) { - if(meta && len == 1) - ttywrite("\033", 1); - ttywrite(buf, len); - } - break; - } + if(len == 0) + return; + + if (len == 1 && e->state & Mod1Mask) + *cp++ = '\033'; + + memcpy(cp, xstr, len); + len = cp - buf + len; } + + ttywrite(buf, len); + if(IS_SET(MODE_ECHO)) + techo(buf, len); } + void cmessage(XEvent *e) { /* See xembed specs @@ -2725,10 +2835,8 @@ cresize(int width, int height) if(height != 0) xw.h = height; - col = (xw.w - 2*borderpx) / xw.cw; - row = (xw.h - 2*borderpx) / 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); @@ -2807,7 +2915,7 @@ main(int argc, char *argv[]) { opt_class = argv[i]; break; case 'e': - /* eat every remaining arguments */ + /* eat all remaining arguments */ if(++i < argc) opt_cmd = &argv[i]; goto run; @@ -2862,6 +2970,7 @@ run: ttynew(); selinit(); run(); + return 0; }