JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
update VERSION.
[st.git] / st.c
diff --git a/st.c b/st.c
index e988696..a6fb766 100644 (file)
--- a/st.c
+++ b/st.c
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
-#include <X11/Xlib.h>
 #include <X11/Xatom.h>
-#include <X11/keysym.h>
+#include <X11/Xlib.h>
 #include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
 
 #if   defined(__linux)
  #include <pty.h>
@@ -31,7 +32,7 @@
 
 #define USAGE \
        "st-" VERSION ", (c) 2010 st engineers\n" \
-       "usage: st [-t title] [-c class] [-e cmd] [-v]\n"
+       "usage: st [-t title] [-c class] [-v] [-e cmd]\n"
 
 /* Arbitrary sizes */
 #define ESC_TITLE_SIZ 256
@@ -151,6 +152,7 @@ typedef struct {
        int ex, ey;
        struct {int x, y;}  b, e;
        char *clip;
+       Atom xtarget;
 } Selection;
 
 #include "config.h"
@@ -247,7 +249,7 @@ static CSIEscape escseq;
 static int cmdfd;
 static pid_t pid;
 static Selection sel;
-static char *opt_cmd   = NULL;
+static char **opt_cmd  = NULL;
 static char *opt_title = NULL;
 static char *opt_class = NULL;
 
@@ -369,6 +371,9 @@ selinit(void) {
        sel.mode = 0;
        sel.bx = -1;
        sel.clip = NULL;
+       sel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
+       if(sel.xtarget == None)
+               sel.xtarget = XA_STRING;
 }
 
 static inline int 
@@ -387,8 +392,8 @@ getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
        if(b) 
                *b = e->xbutton.button;
 
-       *x = e->xbutton.x/xw.cw;
-       *y = e->xbutton.y/xw.ch;
+       *x = (e->xbutton.x - BORDER)/xw.cw;
+       *y = (e->xbutton.y - BORDER)/xw.ch;
        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;
@@ -398,8 +403,8 @@ getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
 void
 bpress(XEvent *e) {
        sel.mode = 1;
-       sel.ex = sel.bx = e->xbutton.x/xw.cw;
-       sel.ey = sel.by = e->xbutton.y/xw.ch;
+       sel.ex = sel.bx = (e->xbutton.x - BORDER)/xw.cw;
+       sel.ey = sel.by = (e->xbutton.y - BORDER)/xw.ch;
 }
 
 void
@@ -419,8 +424,8 @@ selcopy(void) {
                                        memcpy(ptr, term.line[y][x].c, sl);
                                        ptr += sl;
                                }
-                       if(ls)
-                               *ptr = '\n', ptr++;
+                       if(ls && y < sel.e.y)
+                               *ptr++ = '\n';
                }
                *ptr = 0;
        }
@@ -452,7 +457,7 @@ selnotify(XEvent *e) {
 
 void
 selpaste() {
-       XConvertSelection(xw.dpy, XA_PRIMARY, XA_STRING, XA_PRIMARY, xw.win, CurrentTime);
+       XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY, xw.win, CurrentTime);
 }
 
 void
@@ -473,12 +478,12 @@ selrequest(XEvent *e) {
        xa_targets = XInternAtom(xw.dpy, "TARGETS", 0);
        if(xsre->target == xa_targets) {
                /* respond with the supported type */
-               Atom string = XA_STRING;
+               Atom string = sel.xtarget;
                XChangeProperty(xsre->display, xsre->requestor, xsre->property,
                                XA_ATOM, 32, PropModeReplace,
                                (unsigned char *) &string, 1);
                xev.property = xsre->property;
-       } else if(xsre->target == XA_STRING) {
+       } else if(xsre->target == sel.xtarget) {
                XChangeProperty(xsre->display, xsre->requestor, xsre->property,
                                xsre->target, 8, PropModeReplace,
                                (unsigned char *) sel.clip, strlen(sel.clip));
@@ -545,13 +550,14 @@ die(const char *errstr, ...) {
 
 void
 execsh(void) {
-       char *args[] = {getenv("SHELL"), "-i", NULL};
-       if(opt_cmd)
-               args[0] = opt_cmd, args[1] = NULL;
-       else
-               DEFAULT(args[0], SHELL);
+       char **args;
+       char *envshell = getenv("SHELL");
+
+       DEFAULT(envshell, "sh");
        putenv("TERM="TNAME);
+       args = opt_cmd ? opt_cmd : (char*[]){envshell, "-i", NULL};
        execvp(args[0], args);
+       exit(EXIT_FAILURE);
 }
 
 void 
@@ -606,24 +612,31 @@ dump(char c) {
 
 void
 ttyread(void) {
-       char buf[BUFSIZ], *ptr;
+       static char buf[BUFSIZ];
+       static int buflen = 0; 
+       char *ptr;
        char s[UTF_SIZ];
-       int ret, br;
-       static int buflen = 0;
-       long u;
+       int charsize; /* size of utf8 char in bytes */
+       long utf8c;
+       int ret;
 
+       /* append read bytes to unprocessed bytes */
        if((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
                die("Couldn't read from shell: %s\n", SERRNO);
-       else {
-               buflen += ret;
-               for(ptr=buf; buflen>=UTF_SIZ||isfullutf8(ptr,buflen); buflen-=br) {
-                       br = utf8decode(ptr, &u);
-                       utf8encode(&u, s);
-                       tputc(s);
-                       ptr += br;
-               }
-               memcpy(buf, ptr, buflen);
+
+       /* process every complete utf8 char */
+       buflen += ret;
+       ptr = buf;
+       while(buflen >= UTF_SIZ || isfullutf8(ptr,buflen)) {
+               charsize = utf8decode(ptr, &utf8c);
+               utf8encode(&utf8c, s);
+               tputc(s);
+               ptr    += charsize;
+               buflen -= charsize;
        }
+
+       /* keep any uncomplete utf8 char for the next call */
+       memmove(buf, ptr, buflen);
 }
 
 void
@@ -926,7 +939,7 @@ csihandle(void) {
        switch(escseq.mode) {
        default:
        unknown:
-               printf("erresc: unknown csi ");
+               fprintf(stderr, "erresc: unknown csi ");
                csidump();
                /* die(""); */
                break;
@@ -1198,7 +1211,7 @@ tputc(char *c) {
                                term.c.attr.mode &= ~ATTR_GFX;
                                break;
                        default:
-                               printf("esc unhandled charset: ESC ( %c\n", ascii);
+                               fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
                        }
                        term.esc = 0;
                } else {
@@ -1495,6 +1508,7 @@ initfonts(char *fontstr, char *bfontstr)
 void
 xinit(void) {
        XSetWindowAttributes attrs;
+       Cursor cursor;
 
        if(!(xw.dpy = XOpenDisplay(NULL)))
                die("Can't open display\n");
@@ -1542,6 +1556,13 @@ xinit(void) {
        /* gc */
        dc.gc = XCreateGC(xw.dpy, xw.win, 0, NULL);
        
+       /* white cursor, black outline */
+       cursor = XCreateFontCursor(xw.dpy, XC_xterm);
+       XDefineCursor(xw.dpy, xw.win, cursor);
+       XRecolorCursor(xw.dpy, cursor, 
+               &(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff},
+               &(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
+
        XMapWindow(xw.dpy, xw.win);
        xhints();
        XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st");
@@ -1774,12 +1795,10 @@ kpress(XEvent *ev) {
                        /* 3. X lookup  */
                default:
                        if(len > 0) {
-                               buf[sizeof(buf)-1] = '\0';
                                if(meta && len == 1)
                                        ttywrite("\033", 1);
                                ttywrite(buf, len);
-                       } else /* 4. nothing to send */
-                               fprintf(stderr, "errkey: %d\n", (int)ksym);
+                       }
                        break;
                }
 }
@@ -1845,12 +1864,15 @@ main(int argc, char *argv[]) {
                        if(++i < argc) opt_class = argv[i];
                        break;
                case 'e':
-                       if(++i < argc) opt_cmd = argv[i];
+                       if(++i < argc) opt_cmd = &argv[i];
                        break;
                case 'v':
                default:
                        die(USAGE);
                }
+               /* -e eats every remaining arguments */
+               if(opt_cmd)
+                       break;
        }
        setlocale(LC_CTYPE, "");
        tnew(80, 24);