JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
The title can now be set with UTF-8 characters.
[st.git] / st.c
diff --git a/st.c b/st.c
index a440959..0ea51d9 100644 (file)
--- a/st.c
+++ b/st.c
 #define XEMBED_FOCUS_OUT 5
 
 /* Arbitrary sizes */
-#define ESC_BUF_SIZ   256
+#define UTF_SIZ       4
+#define ESC_BUF_SIZ   (128*UTF_SIZ)
 #define ESC_ARG_SIZ   16
-#define STR_BUF_SIZ   256
-#define STR_ARG_SIZ   16
+#define STR_BUF_SIZ   ESC_BUF_SIZ
+#define STR_ARG_SIZ   ESC_ARG_SIZ
 #define DRAW_BUF_SIZ  20*1024
-#define UTF_SIZ       4
 #define XK_ANY_MOD    UINT_MAX
 #define XK_NO_MOD     0
 
@@ -168,7 +168,7 @@ typedef struct {
        int len;               /* raw string length */
        char priv;
        int arg[ESC_ARG_SIZ];
-       int narg;             /* nb of args */
+       int narg;              /* nb of args */
        char mode;
 } CSIEscape;
 
@@ -436,8 +436,8 @@ typedef struct {
  * the current length of used elements.
  */
 
-static Fontcache frc[256];
-static int frccur = 0, frclen = 0;
+static Fontcache frc[1024];
+static int frccur = -1, frclen = 0;
 
 ssize_t
 xwrite(int fd, char *s, size_t len) {
@@ -1390,7 +1390,7 @@ tsetattr(int *attr, int l) {
                case 1:
                        term.c.attr.mode |= ATTR_BOLD;
                        break;
-               case 3: /* enter standout (highlight) */
+               case 3:
                        term.c.attr.mode |= ATTR_ITALIC;
                        break;
                case 4:
@@ -1406,7 +1406,7 @@ tsetattr(int *attr, int l) {
                case 22:
                        term.c.attr.mode &= ~ATTR_BOLD;
                        break;
-               case 23: /* leave standout (highlight) mode */
+               case 23:
                        term.c.attr.mode &= ~ATTR_ITALIC;
                        break;
                case 24:
@@ -1911,12 +1911,13 @@ tputc(char *c, int len) {
 
        if(iofd != -1) {
                if (xwrite(iofd, c, len) < 0) {
-                       fprintf(stderr, "Error writting in %s:%s\n",
+                       fprintf(stderr, "Error writing in %s:%s\n",
                                opt_io, strerror(errno));
                        close(iofd);
                        iofd = -1;
                }
        }
+
        /*
         * STR sequences must be checked before anything else
         * because it can use some control codes as part of the sequence.
@@ -1931,10 +1932,23 @@ tputc(char *c, int len) {
                        strhandle();
                        break;
                default:
-                       strescseq.buf[strescseq.len++] = ascii;
-                       if(strescseq.len+1 >= STR_BUF_SIZ) {
-                               term.esc = 0;
-                               strhandle();
+                       if(strescseq.len + len < sizeof(strescseq.buf)) {
+                               memmove(&strescseq.buf[strescseq.len], c, len);
+                               strescseq.len += len;
+                       } else {
+                       /*
+                        * Here is a bug in terminals. If the user never sends
+                        * some code to stop the str or esc command, then st
+                        * will stop responding. But this is better than
+                        * silently failing with unknown characters. At least
+                        * then users will report back.
+                        *
+                        * In the case users ever get fixed, here is the code:
+                        */
+                       /*
+                        * term.esc = 0;
+                        * strhandle();
+                        */
                        }
                }
                return;
@@ -2406,11 +2420,11 @@ xunloadfonts(void)
         * from the frccur.
         */
        for (i = 0, ip = frccur; i < frclen; i++, ip--) {
-               if (ip <= 0)
+               if (ip < 0)
                        ip = LEN(frc) - 1;
                XftFontClose(xw.dpy, frc[ip].font);
        }
-       frccur = 0;
+       frccur = -1;
        frclen = 0;
 
        XftFontClose(xw.dpy, dc.font.match);
@@ -2497,15 +2511,23 @@ xinit(void) {
        /* double buffering */
        if(!XdbeQueryExtension(xw.dpy, &major, &minor))
                die("Xdbe extension is not present\n");
-       xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeCopied);
+       xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeBackground);
 
        /* Xft rendering context */
        xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
 
        /* input methods */
-       xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
-       if(xw.xim == NULL)
-               die("XOpenIM failed. Could not open input device.\n");
+       if((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+               XSetLocaleModifiers("@im=local");
+               if((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
+                       XSetLocaleModifiers("@im=");
+                       if((xw.xim = XOpenIM(xw.dpy,
+                                       NULL, NULL, NULL)) == NULL) {
+                               die("XOpenIM failed. Could not open input"
+                                       " device.\n");
+                       }
+               }
+       }
        xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
                                           | XIMStatusNothing, XNClientWindow, xw.win,
                                           XNFocusWindow, xw.win, NULL);
@@ -2532,16 +2554,16 @@ xinit(void) {
 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, u8clen, xp, i, frp, frcflags;
+           width = charlen * xw.cw, xp, i;
+       int frp, frcflags;
+       int u8fl, u8fblen, u8cblen, doesexist;
+       char *u8c, *u8fs;
        long u8char;
-       char *u8c;
        Font *font = &dc.font;
-       XftFont *sfont;
        FcResult fcres;
        FcPattern *fcpattern, *fontpattern;
        FcFontSet *fcsets[] = { NULL };
        FcCharSet *fccharset;
-       XGlyphInfo extents;
        Colour *fg = &dc.col[base.fg], *bg = &dc.col[base.bg],
                 *temp, revfg, revbg;
        XRenderColor colfg, colbg;
@@ -2608,11 +2630,6 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
                bg = temp;
        }
 
-       /* Width of the whole string that should be printed. */
-       XftTextExtentsUtf8(xw.dpy, font->match, (FcChar8 *)s, bytelen,
-                       &extents);
-       width = extents.xOff;
-
        /* Intelligent cleaning up of the borders. */
        if(x == 0) {
                xclear(0, (y == 0)? 0 : winy, borderpx,
@@ -2630,85 +2647,111 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
        /* Clean up the region we want to draw to. */
        XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch);
 
-       /*
-        * Step through all UTF-8 characters one by one and search in the font
-        * cache ring buffer, whether there was some font found to display the
-        * unicode value of that UTF-8 character.
-        */
        fcsets[0] = font->set;
-       for (xp = winx; bytelen > 0; ) {
-               u8c = s;
-               u8clen = utf8decode(s, &u8char);
-               s += u8clen;
-               bytelen -= u8clen;
-
-               sfont = font->match;
+       for (xp = winx; bytelen > 0;) {
                /*
-                * Only check the font cache or load new fonts, if the
-                * characters is not represented in main font.
+                * Search for the range in the to be printed string of glyphs
+                * that are in the main font. Then print that range. If
+                * some glyph is found that is not in the font, do the
+                * fallback dance.
                 */
-               if (!XftCharExists(xw.dpy, font->match, u8char)) {
-                       frp = frccur;
-                       /* Search the font cache. */
-                       for (i = 0; i < frclen; i++, frp--) {
-                               if (frp <= 0)
-                                       frp = LEN(frc) - 1;
+               u8fs = s;
+               u8fblen = 0;
+               u8fl = 0;
+               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) {
+                                               u8fl++;
+                                               u8fblen += u8cblen;
+                                       }
+                               }
 
-                               if (frc[frp].c == u8char
-                                       && frc[frp].flags == frcflags) {
-                                       break;
+                               if (u8fl > 0) {
+                                       XftDrawStringUtf8(xw.draw, fg,
+                                                       font->match, xp,
+                                                       winy + font->ascent,
+                                                       (FcChar8 *)u8fs,
+                                                       u8fblen);
+                                       xp += font->width * u8fl;
                                }
+                               break;
                        }
-                       if (i >= frclen) {
-                               /*
-                                * Nothing was found in the cache. Now use
-                                * some dozen of Fontconfig calls to get the
-                                * font for one single character.
-                                */
-                               fcpattern = FcPatternDuplicate(font->pattern);
-                               fccharset = FcCharSetCreate();
-
-                               FcCharSetAddChar(fccharset, u8char);
-                               FcPatternAddCharSet(fcpattern, FC_CHARSET,
-                                               fccharset);
-                               FcPatternAddBool(fcpattern, FC_SCALABLE,
-                                               FcTrue);
-
-                               FcConfigSubstitute(0, fcpattern,
-                                               FcMatchPattern);
-                               FcDefaultSubstitute(fcpattern);
-
-                               fontpattern = FcFontSetMatch(0, fcsets,
-                                               FcTrue, fcpattern, &fcres);
-
-                               frccur++;
-                               frclen++;
-                               if (frccur >= LEN(frc))
-                                       frccur = 0;
-                               if (frclen >= LEN(frc)) {
-                                       frclen = LEN(frc);
-                                       XftFontClose(xw.dpy, frc[frccur].font);
-                               }
 
-                               /*
-                                * Overwrite or create the new cache entry
-                                * entry.
-                                */
-                               frc[frccur].font = XftFontOpenPattern(xw.dpy,
-                                               fontpattern);
-                               frc[frccur].c = u8char;
-                               frc[frccur].flags = frcflags;
+                       u8fl++;
+                       u8fblen += u8cblen;
+               }
+               if (doesexist)
+                       break;
 
-                               FcPatternDestroy(fcpattern);
-                               FcCharSetDestroy(fccharset);
+               frp = frccur;
+               /* Search the font cache. */
+               for (i = 0; i < frclen; i++, frp--) {
+                       if (frp <= 0)
+                               frp = LEN(frc) - 1;
 
-                               frp = frccur;
+                       if (frc[frp].c == u8char
+                                       && frc[frp].flags == frcflags) {
+                               break;
                        }
-                       sfont = frc[frp].font;
                }
 
-               XftDrawStringUtf8(xw.draw, fg, sfont, xp, winy + sfont->ascent,
-                               (FcChar8 *)u8c, u8clen);
+               /* Nothing was found. */
+               if (i >= frclen) {
+                       /*
+                        * Nothing was found in the cache. Now use
+                        * some dozen of Fontconfig calls to get the
+                        * font for one single character.
+                        */
+                       fcpattern = FcPatternDuplicate(font->pattern);
+                       fccharset = FcCharSetCreate();
+
+                       FcCharSetAddChar(fccharset, u8char);
+                       FcPatternAddCharSet(fcpattern, FC_CHARSET,
+                                       fccharset);
+                       FcPatternAddBool(fcpattern, FC_SCALABLE,
+                                       FcTrue);
+
+                       FcConfigSubstitute(0, fcpattern,
+                                       FcMatchPattern);
+                       FcDefaultSubstitute(fcpattern);
+
+                       fontpattern = FcFontSetMatch(0, fcsets,
+                                       FcTrue, fcpattern, &fcres);
+
+                       /*
+                        * Overwrite or create the new cache entry
+                        * entry.
+                        */
+                       frccur++;
+                       frclen++;
+                       if (frccur >= LEN(frc))
+                               frccur = 0;
+                       if (frclen > LEN(frc)) {
+                               frclen = LEN(frc);
+                               XftFontClose(xw.dpy, frc[frccur].font);
+                       }
+
+                       frc[frccur].font = XftFontOpenPattern(xw.dpy,
+                                       fontpattern);
+                       frc[frccur].c = u8char;
+                       frc[frccur].flags = frcflags;
+
+                       FcPatternDestroy(fcpattern);
+                       FcCharSetDestroy(fccharset);
+
+                       frp = frccur;
+               }
+
+               XftDrawStringUtf8(xw.draw, fg, frc[frp].font,
+                               xp, winy + frc[frp].font->ascent,
+                               (FcChar8 *)u8c, u8cblen);
 
                xp += font->width;
        }