JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Add terminfo definitions for terminals with meta key
[st.git] / st.c
diff --git a/st.c b/st.c
index 289ecb8..1b01353 100644 (file)
--- a/st.c
+++ b/st.c
@@ -76,6 +76,14 @@ char *argv0;
 #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg)
 #define IS_SET(flag) ((term.mode & (flag)) != 0)
 #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000)
+#define CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x))
+
+#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
+#define IS_TRUECOL(x)    (1 << 24 & (x))
+#define TRUERED(x)       (((x) & 0xff0000) >> 8)
+#define TRUEGREEN(x)     (((x) & 0xff00))
+#define TRUEBLUE(x)      (((x) & 0xff) << 8)
+
 
 #define VT102ID "\033[?6c"
 
@@ -158,8 +166,8 @@ typedef unsigned short ushort;
 typedef struct {
        char c[UTF_SIZ]; /* character code */
        uchar mode;      /* attribute flags */
-       ushort fg;       /* foreground  */
-       ushort bg;       /* background  */
+       ulong fg;        /* foreground  */
+       ulong bg;        /* background  */
 } Glyph;
 
 typedef Glyph *Line;
@@ -354,7 +362,7 @@ static void tsetdirtattr(int);
 static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 static void techo(char *, int);
-
+static long tdefcolor(int *, int *, int);
 static inline bool match(uint, uint);
 static void ttynew(void);
 static void ttyread(void);
@@ -462,17 +470,12 @@ enum {
 
 typedef struct {
        XftFont *font;
-       long c;
        int flags;
 } Fontcache;
 
-/*
- * Fontcache is a ring buffer, with frccur as current position and frclen as
- * the current length of used elements.
- */
-
-static Fontcache frc[1024];
-static int frccur = -1, frclen = 0;
+/* Fontcache is an array now. A new font will be appended to the array. */
+static Fontcache frc[16];
+static int frclen = 0;
 
 ssize_t
 xwrite(int fd, char *s, size_t len) {
@@ -1623,9 +1626,58 @@ tdeleteline(int n) {
        tscrollup(term.c.y, n);
 }
 
+long
+tdefcolor(int *attr, int *npar, int l) {
+       long idx = -1;
+       uint r, g, b;
+
+       switch (attr[*npar + 1]) {
+       case 2: /* direct colour in RGB space */
+               if (*npar + 4 >= l) {
+                       fprintf(stderr,
+                               "erresc(38): Incorrect number of parameters (%d)\n",
+                               *npar);
+                       break;
+               }
+               r = attr[*npar + 2];
+               g = attr[*npar + 3];
+               b = attr[*npar + 4];
+               *npar += 4;
+               if(!BETWEEN(r, 0, 255) || !BETWEEN(g, 0, 255) || !BETWEEN(b, 0, 255))
+                       fprintf(stderr, "erresc: bad rgb color (%d,%d,%d)\n",
+                               r, g, b);
+               else
+                       idx = TRUECOLOR(r, g, b);
+               break;
+       case 5: /* indexed colour */
+               if (*npar + 2 >= l) {
+                       fprintf(stderr,
+                               "erresc(38): Incorrect number of parameters (%d)\n",
+                               *npar);
+                       break;
+               }
+               *npar += 2;
+               if(!BETWEEN(attr[*npar], 0, 255))
+                       fprintf(stderr, "erresc: bad fgcolor %d\n", attr[*npar]);
+               else
+                       idx = attr[*npar];
+               break;
+       case 0: /* implemented defined (only foreground) */
+       case 1: /* transparent */
+       case 3: /* direct colour in CMY space */
+       case 4: /* direct colour in CMYK space */
+       default:
+               fprintf(stderr,
+                       "erresc(38): gfx attr %d unknown\n", attr[*npar]);
+       }
+
+       return idx;
+}
+
 void
 tsetattr(int *attr, int l) {
        int i;
+       long idx;
 
        for(i = 0; i < l; i++) {
                switch(attr[i]) {
@@ -1670,39 +1722,15 @@ tsetattr(int *attr, int l) {
                        term.c.attr.mode &= ~ATTR_REVERSE;
                        break;
                case 38:
-                       if(i + 2 < l && attr[i + 1] == 5) {
-                               i += 2;
-                               if(BETWEEN(attr[i], 0, 255)) {
-                                       term.c.attr.fg = attr[i];
-                               } else {
-                                       fprintf(stderr,
-                                               "erresc: bad fgcolor %d\n",
-                                               attr[i]);
-                               }
-                       } else {
-                               fprintf(stderr,
-                                       "erresc(38): gfx attr %d unknown\n",
-                                       attr[i]);
-                       }
+                       if ((idx = tdefcolor(attr, &i, l)) >= 0)
+                               term.c.attr.fg = idx;
                        break;
                case 39:
                        term.c.attr.fg = defaultfg;
                        break;
                case 48:
-                       if(i + 2 < l && attr[i + 1] == 5) {
-                               i += 2;
-                               if(BETWEEN(attr[i], 0, 255)) {
-                                       term.c.attr.bg = attr[i];
-                               } else {
-                                       fprintf(stderr,
-                                               "erresc: bad bgcolor %d\n",
-                                               attr[i]);
-                               }
-                       } else {
-                               fprintf(stderr,
-                                       "erresc(48): gfx attr %d unknown\n",
-                                       attr[i]);
-                       }
+                       if ((idx = tdefcolor(attr, &i, l)) >= 0)
+                               term.c.attr.bg = idx;
                        break;
                case 49:
                        term.c.attr.bg = defaultbg;
@@ -2401,6 +2429,7 @@ tputc(char *c, int len) {
                                treset();
                                term.esc = 0;
                                xresettitle();
+                               xloadcols();
                                break;
                        case '=': /* DECPAM -- Application keypad */
                                term.mode |= MODE_APPKEYPAD;
@@ -2562,6 +2591,13 @@ void
 xloadcols(void) {
        int i, r, g, b;
        XRenderColor color = { .alpha = 0xffff };
+       static bool loaded;
+       Colour *cp;
+
+       if(loaded) {
+               for (cp = dc.col; cp < dc.col + LEN(dc.col); ++cp)
+                       XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
+       }
 
        /* load colors [0-15] colors and [256-LEN(colorname)[ (config.h) */
        for(i = 0; i < LEN(colorname); i++) {
@@ -2594,6 +2630,7 @@ xloadcols(void) {
                        die("Could not allocate color %d\n", i);
                }
        }
+       loaded = true;
 }
 
 int
@@ -2741,8 +2778,8 @@ xloadfonts(char *fontstr, int fontsize) {
                die("st: can't open font %s\n", fontstr);
 
        /* Setting character width and height. */
-       xw.cw = dc.font.width;
-       xw.ch = dc.font.height;
+       xw.cw = CEIL(dc.font.width * cwscale);
+       xw.ch = CEIL(dc.font.height * chscale);
 
        FcPatternDel(pattern, FC_SLANT);
        FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
@@ -2781,18 +2818,12 @@ xunloadfont(Font *f) {
 
 void
 xunloadfonts(void) {
-       int i, ip;
+       int i;
 
-       /*
-        * 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)
-                       ip = LEN(frc) - 1;
-               XftFontClose(xw.dpy, frc[ip].font);
+       /* Free the loaded fonts in the font cache.  */
+       for(i = 0; i < frclen; i++) {
+               XftFontClose(xw.dpy, frc[i].font);
        }
-       frccur = -1;
        frclen = 0;
 
        xunloadfont(&dc.font);
@@ -2918,7 +2949,7 @@ void
 xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
        int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
            width = charlen * xw.cw, xp, i;
-       int frp, frcflags;
+       int frcflags;
        int u8fl, u8fblen, u8cblen, doesexist;
        char *u8c, *u8fs;
        long u8char;
@@ -2927,9 +2958,10 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
        FcPattern *fcpattern, *fontpattern;
        FcFontSet *fcsets[] = { NULL };
        FcCharSet *fccharset;
-       Colour *fg, *bg, *temp, revfg, revbg;
+       Colour *fg, *bg, *temp, revfg, revbg, truefg, truebg;
        XRenderColor colfg, colbg;
        Rectangle r;
+       int oneatatime;
 
        frcflags = FRC_NORMAL;
 
@@ -2947,8 +2979,27 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
                if(base.fg == defaultfg)
                        base.fg = defaultunderline;
        }
-       fg = &dc.col[base.fg];
-       bg = &dc.col[base.bg];
+       if(IS_TRUECOL(base.fg)) {
+               colfg.red = TRUERED(base.fg);
+               colfg.green = TRUEGREEN(base.fg);
+               colfg.blue = TRUEBLUE(base.fg);
+               XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg);
+               fg = &truefg;
+       } else {
+               fg = &dc.col[base.fg];
+       }
+
+       if(IS_TRUECOL(base.bg)) {
+               colbg.green = TRUEGREEN(base.bg);
+               colbg.red = TRUERED(base.bg);
+               colbg.blue = TRUEBLUE(base.bg);
+               XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg);
+               bg = &truebg;
+       } else {
+               bg = &dc.col[base.bg];
+       }
+
+
 
        if(base.mode & ATTR_BOLD) {
                if(BETWEEN(base.fg, 0, 7)) {
@@ -3038,15 +3089,16 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
                u8fs = s;
                u8fblen = 0;
                u8fl = 0;
+               oneatatime = font->width != xw.cw;
                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) {
+                       doesexist = XftCharExists(xw.dpy, font->match, u8char);
+                       if(oneatatime || !doesexist || bytelen <= 0) {
+                               if(oneatatime || bytelen <= 0) {
                                        if(doesexist) {
                                                u8fl++;
                                                u8fblen += u8cblen;
@@ -3059,7 +3111,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
                                                        winy + font->ascent,
                                                        (FcChar8 *)u8fs,
                                                        u8fblen);
-                                       xp += font->width * u8fl;
+                                       xp += CEIL(font->width * cwscale * u8fl);
 
                                }
                                break;
@@ -3068,17 +3120,16 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
                        u8fl++;
                        u8fblen += u8cblen;
                }
-               if(doesexist)
+               if(doesexist) {
+                       if (oneatatime);
+                               continue;
                        break;
+               }
 
-               frp = frccur;
                /* Search the font cache. */
-               for(i = 0; i < frclen; i++, frp--) {
-                       if(frp <= 0)
-                               frp = LEN(frc) - 1;
-
-                       if(frc[frp].c == u8char
-                                       && frc[frp].flags == frcflags) {
+               for(i = 0; i < frclen; i++) {
+                       if(XftCharExists(xw.dpy, frc[i].font, u8char)
+                                       && frc[i].flags == frcflags) {
                                break;
                        }
                }
@@ -3113,31 +3164,27 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
                        /*
                         * Overwrite or create the new cache entry.
                         */
-                       frccur++;
-                       frclen++;
-                       if(frccur >= LEN(frc))
-                               frccur = 0;
-                       if(frclen > LEN(frc)) {
-                               frclen = LEN(frc);
-                               XftFontClose(xw.dpy, frc[frccur].font);
+                       if(frclen >= LEN(frc)) {
+                               frclen = LEN(frc) - 1;
+                               XftFontClose(xw.dpy, frc[frclen].font);
                        }
 
-                       frc[frccur].font = XftFontOpenPattern(xw.dpy,
+                       frc[frclen].font = XftFontOpenPattern(xw.dpy,
                                        fontpattern);
-                       frc[frccur].c = u8char;
-                       frc[frccur].flags = frcflags;
+                       frc[frclen].flags = frcflags;
+
+                       i = frclen;
+                       frclen++;
 
                        FcPatternDestroy(fcpattern);
                        FcCharSetDestroy(fccharset);
-
-                       frp = frccur;
                }
 
-               XftDrawStringUtf8(xw.draw, fg, frc[frp].font,
-                               xp, winy + frc[frp].font->ascent,
+               XftDrawStringUtf8(xw.draw, fg, frc[i].font,
+                               xp, winy + frc[i].font->ascent,
                                (FcChar8 *)u8c, u8cblen);
 
-               xp += font->width;
+               xp += CEIL(font->width * cwscale);
        }
 
        /*
@@ -3211,6 +3258,7 @@ xsettitle(char *p) {
        Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
                        &prop);
        XSetWMName(xw.dpy, xw.win, &prop);
+       XFree(prop.value);
 }
 
 void
@@ -3559,8 +3607,8 @@ run(void) {
                        ttyread();
                        if(blinktimeout) {
                                blinkset = tattrset(ATTR_BLINK);
-                               if(!blinkset && term.mode & ATTR_BLINK)
-                                       term.mode &= ~(MODE_BLINK);
+                               if(!blinkset)
+                                       MODBIT(term.mode, 0, MODE_BLINK);
                        }
                }