JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Implementing Back Color Erase (BCE).
[st.git] / st.c
diff --git a/st.c b/st.c
index 979fdc8..5f75c39 100644 (file)
--- a/st.c
+++ b/st.c
@@ -152,7 +152,7 @@ typedef struct {
        uchar state; /* state flags    */
 } Glyph;
 
-typedef Glyph* Line;
+typedef Glyph *Line;
 
 typedef struct {
        Glyph attr;      /* current char attributes */
@@ -213,8 +213,7 @@ typedef struct {
        bool isfixed; /* is fixed geometry? */
        int fx, fy, fw, fh; /* fixed geometry */
        int tw, th; /* tty width and height */
-       int w;  /* window width */
-       int h;  /* window height */
+       int w, h; /* window width and height */
        int ch; /* char height */
        int cw; /* char width  */
        char state; /* focus, redraw, visible */
@@ -284,11 +283,12 @@ typedef struct {
 typedef struct {
        Colour col[LEN(colorname) < 256 ? 256 : LEN(colorname)];
        Font font, bfont, ifont, ibfont;
+       GC gc;
 } DC;
 
 static void die(const char *, ...);
 static void draw(void);
-static void redraw(void);
+static void redraw(int);
 static void drawregion(int, int, int, int);
 static void execsh(void);
 static void sigchld(int);
@@ -303,7 +303,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);
@@ -1113,7 +1113,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 +1157,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 +1177,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];
@@ -1305,7 +1305,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 +1320,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 +1341,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 +1359,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
@@ -1510,7 +1517,7 @@ tsetmode(bool priv, bool set, int *args, int narg) {
                                mode = term.mode;
                                MODBIT(term.mode, set, MODE_REVERSE);
                                if(mode != term.mode)
-                                       redraw();
+                                       redraw(REDRAW_TIMEOUT);
                                break;
                        case 6: /* DECOM -- Origin */
                                MODBIT(term.c.state, set, CURSOR_ORIGIN);
@@ -1542,8 +1549,10 @@ tsetmode(bool priv, bool set, int *args, int narg) {
                        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)
@@ -1662,17 +1671,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 +1692,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 +1724,8 @@ csihandle(void) {
                break;
        case 'X': /* ECH -- Erase <n> 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],
+                               term.c.y, 0);
                break;
        case 'P': /* DCH -- Delete <n> char */
                DEFAULT(csiescseq.arg[0], 1);
@@ -1987,10 +2000,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 */
@@ -2234,6 +2250,14 @@ 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);
+       }
+
        XftDrawChange(xw.draw, xw.buf);
 }
 
@@ -2449,7 +2473,7 @@ xzoom(const Arg *arg)
        xunloadfonts();
        xloadfonts(usedfont, usedfontsize + arg->i);
        cresize(0, 0);
-       draw();
+       redraw(0);
 }
 
 void
@@ -2494,6 +2518,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;
@@ -2512,16 +2537,25 @@ xinit(void) {
                        &attrs);
 
        /* double buffering */
+       /*
        if(XdbeQueryExtension(xw.dpy, &major, &minor)) {
                xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win,
                                XdbeBackground);
                usedbe = True;
        } else {
-               xw.buf = xw.win;
+       */
+               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;
+       /*
        }
+       */
 
        /* Xft rendering context */
-       xw.draw = XftDrawCreate(xw.dpy, xw.win, xw.vis, xw.cmap);
+       xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
 
        /* input methods */
        if((xw.xim =  XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
@@ -2815,13 +2849,16 @@ xresettitle(void) {
 }
 
 void
-redraw(void) {
-       struct timespec tv = {0, REDRAW_TIMEOUT * 1000};
+redraw(int timeout) {
+       struct timespec tv = {0, timeout * 1000};
 
        tfulldirt();
        draw();
-       XSync(xw.dpy, False); /* necessary for a good tput flash */
-       nanosleep(&tv, NULL);
+
+       if(timeout > 0) {
+               nanosleep(&tv, NULL);
+               XSync(xw.dpy, False); /* necessary for a good tput flash */
+       }
 }
 
 void
@@ -2829,8 +2866,14 @@ draw(void) {
        XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
 
        drawregion(0, 0, term.col, term.row);
-       if(usedbe)
+       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);
+       }
 }
 
 void
@@ -2869,6 +2912,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;
@@ -2889,6 +2933,7 @@ expose(XEvent *ev) {
                if(!e->count)
                        xw.state &= ~WIN_REDRAW;
        }
+       redraw(0);
 }
 
 void