X-Git-Url: https://jasonwoof.com/gitweb/?p=st.git;a=blobdiff_plain;f=st.c;h=afa6813989c5b545a94c7b0c346b6aa6510c8e86;hp=7b0fb21e076e41730117dc52ebd736ac7dbfd50b;hb=be7c6d7fb09ff50127332060d771b94a3bc8e44c;hpb=15c2bff9faa87644abf96c19b17133d03d40b974 diff --git a/st.c b/st.c index 7b0fb21..afa6813 100644 --- a/st.c +++ b/st.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -44,7 +43,7 @@ #endif #define USAGE \ - "st " VERSION " (c) 2010-2012 st engineers\n" \ + "st " VERSION " (c) 2010-2013 st engineers\n" \ "usage: st [-v] [-c class] [-f font] [-g geometry] [-o file]" \ " [-t title] [-w windowid] [-e command ...]\n" @@ -61,6 +60,7 @@ #define DRAW_BUF_SIZ 20*1024 #define XK_ANY_MOD UINT_MAX #define XK_NO_MOD 0 +#define XK_SWITCH_MOD (1<<13) #define REDRAW_TIMEOUT (80*1000) /* 80 ms */ @@ -117,7 +117,8 @@ enum term_mode { MODE_KBDLOCK = 256, MODE_HIDE = 512, MODE_ECHO = 1024, - MODE_APPCURSOR = 2048 + MODE_APPCURSOR = 2048, + MODE_MOUSESGR = 4096, }; enum escape_state { @@ -135,6 +136,11 @@ enum window_state { WIN_FOCUSED = 4 }; +enum selection_type { + SEL_REGULAR = 1, + SEL_RECTANGULAR = 2 +}; + /* bit macro */ #undef B0 enum { B0=1, B1=2, B2=4, B3=8, B4=16, B5=32, B6=64, B7=128 }; @@ -152,7 +158,7 @@ typedef struct { uchar state; /* state flags */ } Glyph; -typedef Glyph* Line; +typedef Glyph *Line; typedef struct { Glyph attr; /* current char attributes */ @@ -232,6 +238,7 @@ typedef struct { /* TODO: use better name for vars... */ typedef struct { int mode; + int type; int bx, by; int ex, ey; struct { @@ -259,9 +266,10 @@ typedef struct { } Shortcut; /* function definitions used in config.h */ -static void xzoom(const Arg *); -static void selpaste(const Arg *); +static void clippaste(const Arg *); static void numlock(const Arg *); +static void selpaste(const Arg *); +static void xzoom(const Arg *); /* Config.h for applying patches and the configuration. */ #include "config.h" @@ -303,7 +311,7 @@ static void strhandle(void); static void strparse(void); static void strreset(void); -static void tclearregion(int, int, int, int); +static void tclearregion(int, int, int, int, int); static void tcursor(int); static void tdeletechar(int); static void tdeleteline(int); @@ -340,8 +348,10 @@ static void xclear(int, int, int, int); static void xdrawcursor(void); static void xinit(void); static void xloadcols(void); +static int xsetcolorname(int, const char *); static int xloadfont(Font *, FcPattern *); static void xloadfonts(char *, int); +static void xsettitle(char *); static void xresettitle(void); static void xseturgency(int); static void xsetsel(char*); @@ -414,8 +424,6 @@ static char *opt_embed = NULL; static char *opt_class = NULL; static char *opt_font = NULL; -bool usedbe = False; - static char *usedfont = NULL; static int usedfontsize = 0; @@ -649,10 +657,23 @@ selected(int x, int y) { || (y == sel.e.y && x <= sel.e.x)) || (y == sel.b.y && x >= sel.b.x && (x <= sel.e.x || sel.b.y != sel.e.y)); + switch(sel.type) { + case SEL_REGULAR: + return ((sel.b.y < y && y < sel.e.y) + || (y == sel.e.y && x <= sel.e.x)) + || (y == sel.b.y && x >= sel.b.x + && (x <= sel.e.x || sel.b.y != sel.e.y)); + case SEL_RECTANGULAR: + return ((sel.b.y <= y && y <= sel.e.y) + && (sel.b.x <= x && x <= sel.e.x)); + }; } void getbuttoninfo(XEvent *e) { + int type; + uint state = e->xbutton.state &~Button1Mask; + sel.alt = IS_SET(MODE_ALTSCREEN); sel.ex = x2col(e->xbutton.x); @@ -662,15 +683,22 @@ getbuttoninfo(XEvent *e) { sel.b.y = MIN(sel.by, sel.ey); sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx; sel.e.y = MAX(sel.by, sel.ey); + + sel.type = SEL_REGULAR; + for(type = 1; type < LEN(selmasks); ++type) { + if(match(selmasks[type], state)) { + sel.type = type; + break; + } + } } void mousereport(XEvent *e) { - 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 }; + int x = x2col(e->xbutton.x), y = y2row(e->xbutton.y), + button = e->xbutton.button, state = e->xbutton.state, + len; + char buf[40]; static int ob, ox, oy; /* from urxvt */ @@ -679,7 +707,9 @@ mousereport(XEvent *e) { return; button = ob + 32; ox = x, oy = y; - } else if(e->xbutton.type == ButtonRelease || button == AnyButton) { + } else if(!IS_SET(MODE_MOUSESGR) + && (e->xbutton.type == ButtonRelease + || button == AnyButton)) { button = 3; } else { button -= Button1; @@ -691,11 +721,23 @@ mousereport(XEvent *e) { } } - buf[3] = 32 + button + (state & ShiftMask ? 4 : 0) + button += (state & ShiftMask ? 4 : 0) + (state & Mod4Mask ? 8 : 0) + (state & ControlMask ? 16 : 0); - ttywrite(buf, sizeof(buf)); + len = 0; + if(IS_SET(MODE_MOUSESGR)) { + len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", + button, x+1, y+1, + e->xbutton.type == ButtonRelease ? 'm' : 'M'); + } else if(x < 223 && y < 223) { + len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", + 32+button, 32+x+1, 32+y+1); + } else { + return; + } + + ttywrite(buf, len); } void @@ -709,6 +751,7 @@ bpress(XEvent *e) { draw(); } sel.mode = 1; + sel.type = SEL_REGULAR; sel.ex = sel.bx = x2col(e->xbutton.x); sel.ey = sel.by = y2row(e->xbutton.y); } else if(e->xbutton.button == Button4) { @@ -731,7 +774,8 @@ selcopy(void) { ptr = str = xmalloc(bufsize); /* append every set & selected glyph to the selection */ - for(y = 0; y < term.row; y++) { + for(y = sel.b.y; y < sel.e.y + 1; y++) { + is_selected = 0; gp = &term.line[y][0]; last = gp + term.col; @@ -739,8 +783,11 @@ selcopy(void) { /* nothing */; for(x = 0; gp <= last; x++, ++gp) { - if(!(is_selected = selected(x, y))) + if(!selected(x, y)) { continue; + } else { + is_selected = 1; + } p = (gp->state & GLYPH_SET) ? gp->c : " "; size = utf8size(p); @@ -784,7 +831,17 @@ selpaste(const Arg *dummy) { xw.win, CurrentTime); } -void selclear(XEvent *e) { +void +clippaste(const Arg *dummy) { + Atom clipboard; + + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XConvertSelection(xw.dpy, clipboard, sel.xtarget, XA_PRIMARY, + xw.win, CurrentTime); +} + +void +selclear(XEvent *e) { if(sel.bx == -1) return; sel.bx = -1; @@ -892,7 +949,7 @@ brelease(XEvent *e) { void bmotion(XEvent *e) { - int starty, endy, oldey, oldex; + int oldey, oldex, oldsby, oldsey; if(IS_SET(MODE_MOUSE)) { mousereport(e); @@ -904,12 +961,12 @@ bmotion(XEvent *e) { oldey = sel.ey; oldex = sel.ex; + oldsby = sel.b.y; + oldsey = sel.e.y; getbuttoninfo(e); if(oldey != sel.ey || oldex != sel.ex) { - starty = MIN(oldey, sel.ey); - endy = MAX(oldey, sel.ey); - tsetdirt(starty, endy); + tsetdirt(MIN(sel.b.y, oldsby), MAX(sel.e.y, oldsey)); } } @@ -1113,7 +1170,7 @@ treset(void) { term.bot = term.row - 1; term.mode = MODE_WRAP; - tclearregion(0, 0, term.col-1, term.row-1); + tclearregion(0, 0, term.col-1, term.row-1, 0); tmoveto(0, 0); tcursor(CURSOR_SAVE); } @@ -1157,7 +1214,7 @@ tscrolldown(int orig, int n) { LIMIT(n, 0, term.bot-orig+1); - tclearregion(0, term.bot-n+1, term.col-1, term.bot); + tclearregion(0, term.bot-n+1, term.col-1, term.bot, 0); for(i = term.bot; i >= orig+n; i--) { temp = term.line[i]; @@ -1177,7 +1234,7 @@ tscrollup(int orig, int n) { Line temp; LIMIT(n, 0, term.bot-orig+1); - tclearregion(0, orig, term.col-1, orig+n-1); + tclearregion(0, orig, term.col-1, orig+n-1, 0); for(i = orig; i <= term.bot-n; i++) { temp = term.line[i]; @@ -1201,14 +1258,24 @@ selscroll(int orig, int n) { sel.bx = -1; return; } - if(sel.by < term.top) { - sel.by = term.top; - sel.bx = 0; - } - if(sel.ey > term.bot) { - sel.ey = term.bot; - sel.ex = term.col; - } + switch(sel.type) { + case SEL_REGULAR: + if(sel.by < term.top) { + sel.by = term.top; + sel.bx = 0; + } + if(sel.ey > term.bot) { + sel.ey = term.bot; + sel.ex = term.col; + } + break; + case SEL_RECTANGULAR: + if(sel.by < term.top) + sel.by = term.top; + if(sel.ey > term.bot) + sel.ey = term.bot; + break; + }; sel.b.y = sel.by, sel.b.x = sel.bx; sel.e.y = sel.ey, sel.e.x = sel.ex; } @@ -1305,7 +1372,7 @@ tsetchar(char *c, Glyph *attr, int x, int y) { } void -tclearregion(int x1, int y1, int x2, int y2) { +tclearregion(int x1, int y1, int x2, int y2, int bce) { int x, y, temp; if(x1 > x2) @@ -1320,8 +1387,15 @@ tclearregion(int x1, int y1, int x2, int y2) { for(y = y1; y <= y2; y++) { term.dirty[y] = 1; - for(x = x1; x <= x2; x++) - term.line[y][x].state = 0; + for(x = x1; x <= x2; x++) { + if(bce) { + term.line[y][x] = term.c.attr; + memcpy(term.line[y][x].c, " ", 2); + term.line[y][x].state |= GLYPH_SET; + } else { + term.line[y][x].state = 0; + } + } } } @@ -1334,13 +1408,13 @@ tdeletechar(int n) { term.dirty[term.c.y] = 1; if(src >= term.col) { - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 0); return; } memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph)); - tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); + tclearregion(term.col-n, term.c.y, term.col-1, term.c.y, 0); } void @@ -1352,13 +1426,13 @@ tinsertblank(int n) { term.dirty[term.c.y] = 1; if(dst >= term.col) { - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 0); return; } memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph)); - tclearregion(src, term.c.y, dst - 1, term.c.y); + tclearregion(src, term.c.y, dst - 1, term.c.y, 0); } void @@ -1398,7 +1472,8 @@ tsetattr(int *attr, int l) { case 4: term.c.attr.mode |= ATTR_UNDERLINE; break; - case 5: + case 5: /* slow blink */ + case 6: /* rapid blink */ term.c.attr.mode |= ATTR_BLINK; break; case 7: @@ -1415,6 +1490,7 @@ tsetattr(int *attr, int l) { term.c.attr.mode &= ~ATTR_UNDERLINE; break; case 25: + case 26: term.c.attr.mode &= ~ATTR_BLINK; break; case 27: @@ -1534,16 +1610,23 @@ tsetmode(bool priv, bool set, int *args, int narg) { break; case 1000: /* 1000,1002: enable xterm mouse report */ MODBIT(term.mode, set, MODE_MOUSEBTN); + MODBIT(term.mode, 0, MODE_MOUSEMOTION); break; case 1002: MODBIT(term.mode, set, MODE_MOUSEMOTION); + MODBIT(term.mode, 0, MODE_MOUSEBTN); + break; + case 1006: + MODBIT(term.mode, set, MODE_MOUSESGR); break; case 1049: /* = 1047 and 1048 */ case 47: case 1047: { alt = IS_SET(MODE_ALTSCREEN); - if(alt) - tclearregion(0, 0, term.col-1, term.row-1); + if(alt) { + tclearregion(0, 0, term.col-1, + term.row-1, 0); + } if(set ^ alt) /* set is always 1 or 0 */ tswapscreen(); if(*args != 1049) @@ -1631,7 +1714,7 @@ csihandle(void) { tmoveto(0, term.c.y-csiescseq.arg[0]); break; case 'g': /* TBC -- Tabulation clear */ - switch (csiescseq.arg[0]) { + switch(csiescseq.arg[0]) { case 0: /* clear current tab stop */ term.tabs[term.c.x] = 0; break; @@ -1662,17 +1745,19 @@ csihandle(void) { sel.bx = -1; switch(csiescseq.arg[0]) { case 0: /* below */ - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); - if(term.c.y < term.row-1) - tclearregion(0, term.c.y+1, term.col-1, term.row-1); + tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1); + if(term.c.y < term.row-1) { + tclearregion(0, term.c.y+1, term.col-1, + term.row-1, 1); + } break; case 1: /* above */ if(term.c.y > 1) - tclearregion(0, 0, term.col-1, term.c.y-1); - tclearregion(0, term.c.y, term.c.x, term.c.y); + tclearregion(0, 0, term.col-1, term.c.y-1, 1); + tclearregion(0, term.c.y, term.c.x, term.c.y, 1); break; case 2: /* all */ - tclearregion(0, 0, term.col-1, term.row-1); + tclearregion(0, 0, term.col-1, term.row-1, 1); break; default: goto unknown; @@ -1681,13 +1766,14 @@ csihandle(void) { case 'K': /* EL -- Clear line */ switch(csiescseq.arg[0]) { case 0: /* right */ - tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); + tclearregion(term.c.x, term.c.y, term.col-1, + term.c.y, 1); break; case 1: /* left */ - tclearregion(0, term.c.y, term.c.x, term.c.y); + tclearregion(0, term.c.y, term.c.x, term.c.y, 1); break; case 2: /* all */ - tclearregion(0, term.c.y, term.col-1, term.c.y); + tclearregion(0, term.c.y, term.col-1, term.c.y, 1); break; } break; @@ -1712,7 +1798,8 @@ csihandle(void) { break; case 'X': /* ECH -- Erase char */ DEFAULT(csiescseq.arg[0], 1); - tclearregion(term.c.x, term.c.y, term.c.x + csiescseq.arg[0], term.c.y); + tclearregion(term.c.x, term.c.y, + term.c.x + csiescseq.arg[0] - 1, term.c.y, 1); break; case 'P': /* DCH -- Delete char */ DEFAULT(csiescseq.arg[0], 1); @@ -1782,32 +1869,37 @@ csireset(void) { void strhandle(void) { - char *p; + char *p = NULL; + int i, j, narg; - /* - * TODO: make this being useful in case of color palette change. - */ strparse(); - - p = strescseq.buf; + narg = strescseq.narg; switch(strescseq.type) { case ']': /* OSC -- Operating System Command */ - switch(p[0]) { - case '0': - case '1': - case '2': - /* - * TODO: Handle special chars in string, like umlauts. - */ - if(p[1] == ';') { - XStoreName(xw.dpy, xw.win, strescseq.buf+2); - } - break; - case ';': - XStoreName(xw.dpy, xw.win, strescseq.buf+1); + switch(i = atoi(strescseq.args[0])) { + case 0: + case 1: + case 2: + if(narg > 1) + xsettitle(strescseq.args[1]); break; - case '4': /* TODO: Set color (arg0) to "rgb:%hexr/$hexg/$hexb" (arg1) */ + case 4: /* color set */ + if(narg < 3) + break; + p = strescseq.args[2]; + /* fall through */ + case 104: /* color reset, here p = NULL */ + j = (narg > 1) ? atoi(strescseq.args[1]) : -1; + if (!xsetcolorname(j, p)) { + fprintf(stderr, "erresc: invalid color %s\n", p); + } else { + /* + * TODO if defaultbg color is changed, borders + * are dirty + */ + redraw(0); + } break; default: fprintf(stderr, "erresc: unknown str "); @@ -1816,7 +1908,7 @@ strhandle(void) { } break; case 'k': /* old title set compatibility */ - XStoreName(xw.dpy, xw.win, strescseq.buf); + xsettitle(strescseq.args[0]); break; case 'P': /* DSC -- Device Control String */ case '_': /* APC -- Application Program Command */ @@ -1835,7 +1927,19 @@ strparse(void) { * TODO: Implement parsing like for CSI when required. * Format: ESC type cmd ';' arg0 [';' argn] ESC \ */ - return; + int narg = 0; + char *start = strescseq.buf, *end = start + strescseq.len; + strescseq.args[0] = start; + while(start < end && narg < LEN(strescseq.args)) { + start = memchr(start, ';', end - start); + if(!start) + break; + *start++ = '\0'; + if(start < end) { + strescseq.args[++narg] = start; + } + } + strescseq.narg = narg + 1; } void @@ -1892,7 +1996,7 @@ techo(char *buf, int len) { if(c == '\033') { /* escape */ tputc("^", 1); tputc("[", 1); - } else if (c < '\x20') { /* control code */ + } else if(c < '\x20') { /* control code */ if(c != '\n' && c != '\r' && c != '\t') { c |= '\x40'; tputc("^", 1); @@ -1902,7 +2006,7 @@ techo(char *buf, int len) { break; } } - if (len) + if(len) tputc(buf, len); } @@ -1912,7 +2016,7 @@ tputc(char *c, int len) { bool control = ascii < '\x20' || ascii == 0177; if(iofd != -1) { - if (xwrite(iofd, c, len) < 0) { + if(xwrite(iofd, c, len) < 0) { fprintf(stderr, "Error writing in %s:%s\n", opt_io, strerror(errno)); close(iofd); @@ -1987,10 +2091,13 @@ tputc(char *c, int len) { term.esc = ESC_START; return; case '\016': /* SO */ - term.c.attr.mode |= ATTR_GFX; - return; case '\017': /* SI */ - term.c.attr.mode &= ~ATTR_GFX; + /* + * Different charsets are hard to handle. Applications + * should use the right alt charset escapes for the + * only reason they still exist: line drawing. The + * rest is incompatible history st should not support. + */ return; case '\032': /* SUB */ case '\030': /* CAN */ @@ -2171,9 +2278,11 @@ tresize(int col, int row) { /* free unneeded rows */ i = 0; if(slide > 0) { - /* slide screen to keep cursor where we expect it - + /* + * slide screen to keep cursor where we expect it - * tscrollup would work here, but we can optimize to - * memmove because we're freeing the earlier lines */ + * memmove because we're freeing the earlier lines + */ for(/* i = 0 */; i < slide; i++) { free(term.line[i]); free(term.alt[i]); @@ -2234,21 +2343,24 @@ xresize(int col, int row) { xw.tw = MAX(1, col * xw.cw); xw.th = MAX(1, row * xw.ch); - if(!usedbe) { - XFreePixmap(xw.dpy, xw.buf); - xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, - DefaultDepth(xw.dpy, xw.scr)); - XSetForeground(xw.dpy, dc.gc, 0); - XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h); - } + XFreePixmap(xw.dpy, xw.buf); + xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, + DefaultDepth(xw.dpy, xw.scr)); + XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h); XftDrawChange(xw.draw, xw.buf); } +static inline ushort +sixd_to_16bit(int x) { + return x == 0 ? 0 : 0x3737 + 0x2828 * x; +} + void xloadcols(void) { int i, r, g, b; - XRenderColor color = { .alpha = 0 }; + XRenderColor color = { .alpha = 0xffff }; /* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */ for(i = 0; i < LEN(colorname); i++) { @@ -2263,9 +2375,9 @@ xloadcols(void) { for(i = 16, r = 0; r < 6; r++) { for(g = 0; g < 6; g++) { for(b = 0; b < 6; b++) { - color.red = r == 0 ? 0 : 0x3737 + 0x2828 * r; - color.green = g == 0 ? 0 : 0x3737 + 0x2828 * g; - color.blue = b == 0 ? 0 : 0x3737 + 0x2828 * b; + color.red = sixd_to_16bit(r); + color.green = sixd_to_16bit(g); + color.blue = sixd_to_16bit(b); if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i])) { die("Could not allocate color %d\n", i); } @@ -2283,6 +2395,38 @@ xloadcols(void) { } } +int +xsetcolorname(int x, const char *name) { + XRenderColor color = { .alpha = 0xffff }; + Colour colour; + if (x < 0 || x > LEN(colorname)) + return -1; + if(!name) { + if(16 <= x && x < 16 + 216) { + 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); + color.blue = sixd_to_16bit(b); + if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &colour)) + return 0; /* something went wrong */ + dc.col[x] = colour; + return 1; + } else if (16 + 216 <= x && x < 256) { + 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 */ + dc.col[x] = colour; + return 1; + } else { + name = colorname[x]; + } + } + if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &colour)) + return 0; + dc.col[x] = colour; + return 1; +} + void xtermclear(int col1, int row1, int col2, int row2) { XftDrawRect(xw.draw, @@ -2403,34 +2547,34 @@ xloadfonts(char *fontstr, int fontsize) { xw.cw = dc.font.width; xw.ch = dc.font.height; - 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)) + if(xloadfont(&dc.ifont, pattern)) die("st: can't open font %s\n", fontstr); FcPatternDel(pattern, FC_WEIGHT); - if(xloadfont(&dc.ifont, pattern)) + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + if(xloadfont(&dc.ibfont, pattern)) + die("st: can't open font %s\n", fontstr); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if(xloadfont(&dc.bfont, pattern)) die("st: can't open font %s\n", fontstr); FcPatternDestroy(pattern); } void -xunloadfonts(void) -{ +xunloadfonts(void) { int i, ip; /* * Free the loaded fonts in the font cache. This is done backwards * from the frccur. */ - for (i = 0, ip = frccur; i < frclen; i++, ip--) { - if (ip < 0) + for(i = 0, ip = frccur; i < frclen; i++, ip--) { + if(ip < 0) ip = LEN(frc) - 1; XftFontClose(xw.dpy, frc[ip].font); } @@ -2452,8 +2596,7 @@ xunloadfonts(void) } void -xzoom(const Arg *arg) -{ +xzoom(const Arg *arg) { xunloadfonts(); xloadfonts(usedfont, usedfontsize + arg->i); cresize(0, 0); @@ -2463,9 +2606,10 @@ xzoom(const Arg *arg) void xinit(void) { XSetWindowAttributes attrs; + XGCValues gcvalues; Cursor cursor; Window parent; - int sw, sh, major, minor; + int sw, sh; if(!(xw.dpy = XOpenDisplay(NULL))) die("Can't open display\n"); @@ -2473,7 +2617,7 @@ xinit(void) { xw.vis = XDefaultVisual(xw.dpy, xw.scr); /* font */ - if (!FcInit()) + if(!FcInit()) die("Could not init fontconfig.\n"); usedfont = (opt_font == NULL)? font : opt_font; @@ -2502,6 +2646,7 @@ xinit(void) { xw.fy = 0; } + /* Events */ attrs.background_pixel = dc.col[defaultbg].pixel; attrs.border_pixel = dc.col[defaultbg].pixel; attrs.bit_gravity = NorthWestGravity; @@ -2519,23 +2664,14 @@ xinit(void) { | CWColormap, &attrs); - /* double buffering */ - /* - if(XdbeQueryExtension(xw.dpy, &major, &minor)) { - xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, - XdbeBackground); - usedbe = True; - } else { - */ - dc.gc = XCreateGC(xw.dpy, parent, 0, 0); - xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, - DefaultDepth(xw.dpy, xw.scr)); - XSetForeground(xw.dpy, dc.gc, 0); - XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h); - //xw.buf = xw.win; - /* - } - */ + memset(&gcvalues, 0, sizeof(gcvalues)); + gcvalues.graphics_exposures = False; + dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, + &gcvalues); + xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, + DefaultDepth(xw.dpy, xw.scr)); + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h); /* Xft rendering context */ xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); @@ -2672,7 +2808,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch); fcsets[0] = font->set; - for (xp = winx; bytelen > 0;) { + for(xp = winx; bytelen > 0;) { /* * Search for the range in the to be printed string of glyphs * that are in the main font. Then print that range. If @@ -2682,22 +2818,22 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { u8fs = s; u8fblen = 0; u8fl = 0; - for (;;) { + for(;;) { u8c = s; u8cblen = utf8decode(s, &u8char); s += u8cblen; bytelen -= u8cblen; doesexist = XftCharIndex(xw.dpy, font->match, u8char); - if (!doesexist || bytelen <= 0) { - if (bytelen <= 0) { - if (doesexist) { + if(!doesexist || bytelen <= 0) { + if(bytelen <= 0) { + if(doesexist) { u8fl++; u8fblen += u8cblen; } } - if (u8fl > 0) { + if(u8fl > 0) { XftDrawStringUtf8(xw.draw, fg, font->match, xp, winy + font->ascent, @@ -2711,23 +2847,23 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { u8fl++; u8fblen += u8cblen; } - if (doesexist) + if(doesexist) break; frp = frccur; /* Search the font cache. */ - for (i = 0; i < frclen; i++, frp--) { - if (frp <= 0) + for(i = 0; i < frclen; i++, frp--) { + if(frp <= 0) frp = LEN(frc) - 1; - if (frc[frp].c == u8char + if(frc[frp].c == u8char && frc[frp].flags == frcflags) { break; } } /* Nothing was found. */ - if (i >= frclen) { + if(i >= frclen) { /* * Nothing was found in the cache. Now use * some dozen of Fontconfig calls to get the @@ -2755,9 +2891,9 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { */ frccur++; frclen++; - if (frccur >= LEN(frc)) + if(frccur >= LEN(frc)) frccur = 0; - if (frclen > LEN(frc)) { + if(frclen > LEN(frc)) { frclen = LEN(frc); XftFontClose(xw.dpy, frc[frccur].font); } @@ -2826,9 +2962,19 @@ xdrawcursor(void) { } } + +void +xsettitle(char *p) { + XTextProperty prop; + + Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + &prop); + XSetWMName(xw.dpy, xw.win, &prop); +} + void xresettitle(void) { - XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st"); + xsettitle(opt_title ? opt_title : "st"); } void @@ -2846,17 +2992,12 @@ redraw(int timeout) { void draw(void) { - XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}}; - drawregion(0, 0, term.col, term.row); - if(usedbe) { - XdbeSwapBuffers(xw.dpy, swpinfo, 1); - } else { - XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w, - xw.h, 0, 0); - XSetForeground(xw.dpy, dc.gc, 0); - XSync(xw.dpy, False); - } + XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w, + xw.h, 0, 0); + XSetForeground(xw.dpy, dc.gc, + dc.col[IS_SET(MODE_REVERSE)? + defaultfg : defaultbg].pixel); } void @@ -2895,6 +3036,7 @@ drawregion(int x1, int y1, int x2, int y2) { ox = x; base = new; } + sl = utf8size(new.c); memcpy(buf+ib, new.c, sl); ib += sl; @@ -2946,6 +3088,11 @@ xseturgency(int add) { void focus(XEvent *ev) { + XFocusChangeEvent *e = &ev->xfocus; + + if(e->mode == NotifyGrab) + return; + if(ev->type == FocusIn) { XSetICFocus(xw.xic); xw.state |= WIN_FOCUSED; @@ -2958,6 +3105,8 @@ focus(XEvent *ev) { 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) @@ -3032,7 +3181,7 @@ kpress(XEvent *ev) { Status status; Shortcut *bp; - if (IS_SET(MODE_KBDLOCK)) + if(IS_SET(MODE_KBDLOCK)) return; len = XmbLookupString(xw.xic, e, xstr, sizeof(xstr), &ksym, &status); @@ -3054,7 +3203,7 @@ kpress(XEvent *ev) { if(len == 0) return; - if (len == 1 && e->state & Mod1Mask) + if(len == 1 && e->state & Mod1Mask) *cp++ = '\033'; memcpy(cp, xstr, len); @@ -3069,8 +3218,10 @@ kpress(XEvent *ev) { void cmessage(XEvent *e) { - /* See xembed specs - http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html */ + /* + * See xembed specs + * http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html + */ if(e->xclient.message_type == xw.xembed && e->xclient.format == 32) { if(e->xclient.data.l[1] == XEMBED_FOCUS_IN) { xw.state |= WIN_FOCUSED; @@ -3086,8 +3237,7 @@ cmessage(XEvent *e) { } void -cresize(int width, int height) -{ +cresize(int width, int height) { int col, row; if(width != 0) @@ -3115,10 +3265,12 @@ void run(void) { XEvent ev; fd_set rfd; - int xfd = XConnectionNumber(xw.dpy), i; - struct timeval drawtimeout, *tv = NULL; + int xfd = XConnectionNumber(xw.dpy), xev; + struct timeval drawtimeout, *tv = NULL, now, last; - for(i = 0;; i++) { + gettimeofday(&last, NULL); + + for(xev = actionfps;;) { FD_ZERO(&rfd); FD_SET(cmdfd, &rfd); FD_SET(xfd, &rfd); @@ -3128,35 +3280,36 @@ run(void) { die("select failed: %s\n", SERRNO); } - /* - * Stop after a certain number of reads so the user does not - * feel like the system is stuttering. - */ - if(i < 1000 && FD_ISSET(cmdfd, &rfd)) { + gettimeofday(&now, NULL); + drawtimeout.tv_sec = 0; + drawtimeout.tv_usec = (1000/xfps) * 1000; + tv = &drawtimeout; + + if(FD_ISSET(cmdfd, &rfd)) ttyread(); - /* - * Just wait a bit so it isn't disturbing the - * user and the system is able to write something. - */ - drawtimeout.tv_sec = 0; - drawtimeout.tv_usec = 5; - tv = &drawtimeout; - continue; - } - i = 0; - tv = NULL; + if(FD_ISSET(xfd, &rfd)) + xev = actionfps; - while(XPending(xw.dpy)) { - XNextEvent(xw.dpy, &ev); - if(XFilterEvent(&ev, None)) - continue; - if(handler[ev.type]) - (handler[ev.type])(&ev); - } + if(TIMEDIFF(now, last) > \ + (xev ? (1000/xfps) : (1000/actionfps))) { + while(XPending(xw.dpy)) { + XNextEvent(xw.dpy, &ev); + if(XFilterEvent(&ev, None)) + continue; + if(handler[ev.type]) + (handler[ev.type])(&ev); + } - draw(); - XFlush(xw.dpy); + draw(); + XFlush(xw.dpy); + last = now; + + if(xev && !FD_ISSET(xfd, &rfd)) + xev--; + if(!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) + tv = NULL; + } } }