X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=st.c;h=c2f294a94f37fba153da80f3c68184a996b3bfa0;hb=591d147af7d59f31a68513f613124d49f25f9859;hp=f8d2257a270e09aac49c45083e08ef62cd06c26d;hpb=ce3f4fc647be3ab28f934db9365445a56ebd85bf;p=st.git diff --git a/st.c b/st.c index f8d2257..c2f294a 100644 --- a/st.c +++ b/st.c @@ -20,6 +20,14 @@ #include #include +#if defined(__linux) + #include +#elif defined(__OpenBSD__) || defined(__NetBSD__) + #include +#elif defined(__FreeBSD__) || defined(__DragonFly__) + #include +#endif + /* Arbitrary sizes */ #define ESC_TITLE_SIZ 256 #define ESC_BUF_SIZ 256 @@ -34,13 +42,15 @@ #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg) +#define IS_SET(flag) (term.mode & (flag)) /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */ enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 }; -enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HIDE, CURSOR_DRAW, +enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_SAVE, CURSOR_LOAD }; +enum { CURSOR_DEFAULT = 0, CURSOR_HIDE = 1, CURSOR_WRAPNEXT = 2 }; enum { GLYPH_SET=1, GLYPH_DIRTY=2 }; -enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4 }; +enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8 }; enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 }; enum { SCREEN_UPDATE, SCREEN_REDRAW }; @@ -58,6 +68,7 @@ typedef struct { Glyph attr; /* current char attributes */ int x; int y; + char state; } TCursor; /* CSI Escape sequence structs */ @@ -75,9 +86,9 @@ typedef struct { typedef struct { int row; /* nb row */ int col; /* nb col */ - Line* line; /* screen */ + Line* line; /* screen */ + Line* alt; /* alternate screen */ TCursor c; /* cursor */ - char hidec; int top; /* top scroll limit */ int bot; /* bottom scroll limit */ int mode; /* terminal mode flags */ @@ -98,6 +109,7 @@ typedef struct { int bufh; /* pixmap height */ int ch; /* char height */ int cw; /* char width */ + int hasfocus; } XWindow; typedef struct { @@ -113,6 +125,14 @@ typedef struct { GC gc; } DC; +typedef struct { + int mode; + int bx, by; + int ex, ey; + int b[2], e[2]; + char *clip; +} Selection; + #include "config.h" static void die(const char *errstr, ...); @@ -128,7 +148,6 @@ static void csireset(void); static void tclearregion(int, int, int, int); static void tcursor(int); -static void tmovecursor(int); static void tdeletechar(int); static void tdeleteline(int); static void tinsertblank(int); @@ -136,36 +155,50 @@ static void tinsertblankline(int); static void tmoveto(int, int); static void tnew(int, int); static void tnewline(void); +static void tputtab(void); static void tputc(char); static void tputs(char*, int); static void treset(void); static void tresize(int, int); -static void tscroll(void); static void tscrollup(int); static void tscrolldown(int); static void tsetattr(int*, int); static void tsetchar(char); static void tsetscroll(int, int); +static void tswapscreen(void); static void ttynew(void); static void ttyread(void); static void ttyresize(int, int); static void ttywrite(const char *, size_t); +static void xdraws(char *, Glyph, int, int, int); +static void xhints(void); static void xclear(int, int, int, int); -static void xcursor(int); +static void xdrawcursor(void); static void xinit(void); static void xloadcols(void); +static void xseturgency(int); static void expose(XEvent *); static char* kmap(KeySym); static void kpress(XEvent *); static void resize(XEvent *); +static void focus(XEvent *); +static void brelease(XEvent *); +static void bpress(XEvent *); +static void bmotion(XEvent *); + static void (*handler[LASTEvent])(XEvent *) = { [KeyPress] = kpress, [Expose] = expose, - [ConfigureNotify] = resize + [ConfigureNotify] = resize, + [FocusIn] = focus, + [FocusOut] = focus, + [MotionNotify] = bmotion, + [ButtonPress] = bpress, + [ButtonRelease] = brelease, }; /* Globals */ @@ -175,7 +208,94 @@ static Term term; static CSIEscape escseq; static int cmdfd; static pid_t pid; -static int running; +static Selection sel; + +void +selinit(void) { + sel.mode = 0; + sel.bx = -1; + sel.clip = NULL; +} + +static inline int selected(int x, int y) { + if ((sel.ey==y && sel.by==y)) { + int bx = MIN(sel.bx, sel.ex); + int ex = MAX(sel.bx, sel.ex); + return (x>=bx && x<=ex); + } + return (((y>sel.b[1] && y=sel.b[0] && (x<=sel.e[0] || sel.b[1]!=sel.e[1]))); +} + +static void getbuttoninfo(XEvent *e, int *b, int *x, int *y) { + if(b) *b = e->xbutton.state, + *b=*b==4096?5:*b==2048?4:*b==1024?3:*b==512?2:*b==256?1:-1; + *x = e->xbutton.x/xw.cw; + *y = e->xbutton.y/xw.ch; + sel.b[0] = sel.byxbutton.x/xw.cw; + sel.ey = sel.by = e->xbutton.y/xw.ch; +} + +static char *getseltext() { + char *str, *ptr; + int ls, x, y, sz; + if(sel.bx==-1) + return NULL; + sz = ((term.col+1) * (sel.e[1]-sel.b[1]+1)); + ptr = str = malloc (sz); + for(y = 0; y < term.row; y++) { + for(x = 0; x < term.col; x++) { + if(term.line[y][x].state & GLYPH_SET && (ls=selected(x, y))) + *ptr = term.line[y][x].c, ptr++; + } + if (ls) + *ptr = '\n', ptr++; + } + *ptr = 0; + return str; +} + +/* TODO: use X11 clipboard */ +static void selcopy(char *str) { + free(sel.clip); + sel.clip = str; +} + +static void selpaste() { + if(sel.clip) + ttywrite(sel.clip, strlen(sel.clip)); +} + +/* TODO: doubleclick to select word */ +static void brelease(XEvent *e) { + int b; + sel.mode = 0; + getbuttoninfo(e, &b, &sel.ex, &sel.ey); + if(sel.bx==sel.ex && sel.by==sel.ey) { + sel.bx = -1; + if(b==2) + selpaste(); + } else { + if(b==1) + selcopy(getseltext()); + } + draw(1); +} + +static void bmotion(XEvent *e) { + if (sel.mode) { + getbuttoninfo(e, NULL, &sel.ex, &sel.ey); + draw(1); + } +} #ifdef DEBUG void @@ -210,20 +330,11 @@ die(const char *errstr, ...) { void execsh(void) { char *args[3] = {getenv("SHELL"), "-i", NULL}; - DEFAULT(args[0], "/bin/sh"); /* default shell if getenv() failed */ + DEFAULT(args[0], SHELL); /* if getenv() failed */ putenv("TERM=" TNAME); execvp(args[0], args); } -void -xbell(void) { /* visual bell */ - XRectangle r = { BORDER, BORDER, xw.bufw, xw.bufh }; - XSetForeground(xw.dis, dc.gc, dc.col[BellCol]); - XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1); - /* usleep(30000); */ - draw(SCREEN_REDRAW); -} - void sigchld(int a) { int stat = 0; @@ -238,19 +349,12 @@ sigchld(int a) { void ttynew(void) { int m, s; - char *pts; - - if((m = posix_openpt(O_RDWR | O_NOCTTY)) < 0) - die("openpt failed: %s\n", SERRNO); - if(grantpt(m) < 0) - die("grandpt failed: %s\n", SERRNO); - if(unlockpt(m) < 0) - die("unlockpt failed: %s\n", SERRNO); - if(!(pts = ptsname(m))) - die("ptsname failed: %s\n", SERRNO); - if((s = open(pts, O_RDWR | O_NOCTTY)) < 0) - die("Couldn't open slave: %s\n", SERRNO); - fcntl(s, F_SETFL, O_NDELAY); + + /* seems to work fine on linux, openbsd and freebsd */ + struct winsize w = {term.row, term.col, 0, 0}; + if(openpty(&m, &s, NULL, NULL, &w) < 0) + die("openpty failed: %s\n", SERRNO); + switch(pid = fork()) { case -1: die("fork failed\n"); @@ -261,7 +365,9 @@ ttynew(void) { dup2(s, STDOUT_FILENO); dup2(s, STDERR_FILENO); if(ioctl(s, TIOCSCTTY, NULL) < 0) - die("ioctl TTIOCSTTY failed: %s\n", SERRNO); + die("ioctl TIOCSCTTY failed: %s\n", SERRNO); + close(s); + close(m); execsh(); break; default: @@ -319,44 +425,37 @@ tcursor(int mode) { void treset(void) { - term.c.attr.mode = ATTR_NULL; - term.c.attr.fg = DefaultFG; - term.c.attr.bg = DefaultBG; - term.c.x = term.c.y = 0; - term.hidec = 0; + term.c = (TCursor){{ + .mode = ATTR_NULL, + .fg = DefaultFG, + .bg = DefaultBG + }, .x = 0, .y = 0, .state = CURSOR_DEFAULT}; + term.top = 0, term.bot = term.row - 1; term.mode = MODE_WRAP; tclearregion(0, 0, term.col-1, term.row-1); } void -tnew(int col, int row) { /* screen size */ +tnew(int col, int row) { + /* set screen size */ term.row = row, term.col = col; - term.top = 0, term.bot = term.row - 1; - /* mode */ - term.mode = MODE_WRAP; - /* cursor */ - term.c.attr.mode = ATTR_NULL; - term.c.attr.fg = DefaultFG; - term.c.attr.bg = DefaultBG; - term.c.x = term.c.y = 0; - term.hidec = 0; - /* allocate screen */ - term.line = calloc(term.row, sizeof(Line)); - for(row = 0 ; row < term.row; row++) - term.line[row] = calloc(term.col, sizeof(Glyph)); + term.line = malloc(term.row * sizeof(Line)); + term.alt = malloc(term.row * sizeof(Line)); + for(row = 0 ; row < term.row; row++) { + term.line[row] = malloc(term.col * sizeof(Glyph)); + term.alt [row] = malloc(term.col * sizeof(Glyph)); + } + /* setup screen */ + treset(); } -/* TODO: Replace with scrollup/scolldown */ void -tscroll(void) { - Line temp = term.line[term.top]; - int i; - - for(i = term.top; i < term.bot; i++) - term.line[i] = term.line[i+1]; - memset(temp, 0, sizeof(Glyph) * term.col); - term.line[term.bot] = temp; +tswapscreen(void) { + Line* tmp = term.line; + term.line = term.alt; + term.alt = tmp; + term.mode ^= MODE_ALTSCREEN; } void @@ -385,18 +484,18 @@ tscrollup (int n) { for(i = 0; i < n; i++) memset(term.line[term.top+i], 0, term.col*sizeof(Glyph)); - for(i = term.top; i <= term.bot-n; i++) { + for(i = term.top; i <= term.bot-n; i++) { temp = term.line[i]; term.line[i] = term.line[i+n]; term.line[i+n] = temp; - } + } } void tnewline(void) { int y = term.c.y + 1; if(y > term.bot) - tscroll(), y = term.bot; + tscrollup(1), y = term.bot; tmoveto(0, y); } @@ -426,42 +525,14 @@ csiparse(void) { void tmoveto(int x, int y) { - term.c.x = x < 0 ? 0 : x >= term.col ? term.col-1 : x; - term.c.y = y < 0 ? 0 : y >= term.row ? term.row-1 : y; + LIMIT(x, 0, term.col-1); + LIMIT(y, 0, term.row-1); + term.c.state &= ~CURSOR_WRAPNEXT; + term.c.x = x; + term.c.y = y; } void -tmovecursor(int dir) { - int xf = term.c.x, yf = term.c.y; - - switch(dir) { - case CURSOR_UP: - yf--; - break; - case CURSOR_DOWN: - yf++; - break; - case CURSOR_LEFT: - xf--; - if(term.mode & MODE_WRAP && xf < 0) { - xf = term.col-1, yf--; - if(yf < term.top) - yf = term.top, xf = 0; - } - break; - case CURSOR_RIGHT: - xf++; - if(term.mode & MODE_WRAP && xf >= term.col) { - xf = 0, yf++; - if(yf > term.bot) - yf = term.bot, tscroll(); - } - break; - } - tmoveto(xf, yf); -} - -void tsetchar(char c) { term.line[term.c.y][term.c.x] = term.c.attr; term.line[term.c.y][term.c.x].c = c; @@ -497,21 +568,21 @@ tdeletechar(int n) { return; } memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph)); - tclearregion(term.col-size, term.c.y, term.col-1, term.c.y); + tclearregion(term.col-n, term.c.y, term.col-1, term.c.y); } void tinsertblank(int n) { int src = term.c.x; int dst = src + n; - int size = term.col - n - src; + int size = term.col - dst; if(dst >= term.col) { tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); return; } memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * sizeof(Glyph)); - tclearregion(src, term.c.y, dst, term.c.y); + tclearregion(src, term.c.y, dst - 1, term.c.y); } void @@ -712,7 +783,6 @@ csihandle(void) { case 2: /* all */ tclearregion(0, 0, term.col-1, term.row-1); break; - case 3: /* XXX: erase saved lines (xterm) */ default: goto unknown; } @@ -754,12 +824,18 @@ csihandle(void) { case 12: /* att610 -- Stop blinking cursor (IGNORED) */ break; case 25: - term.hidec = 1; + term.c.state |= CURSOR_HIDE; break; - case 1048: /* XXX: no alt. screen to erase/save */ - case 1049: + case 1049: /* = 1047 and 1048 */ + case 1047: + if(IS_SET(MODE_ALTSCREEN)) { + tclearregion(0, 0, term.col-1, term.row-1); + tswapscreen(); + } + if(escseq.arg[0] == 1047) + break; + case 1048: tcursor(CURSOR_LOAD); - tclearregion(0, 0, term.col-1, term.row-1); break; default: goto unknown; @@ -803,12 +879,18 @@ csihandle(void) { case 12: /* att610 -- Start blinking cursor (IGNORED) */ break; case 25: - term.hidec = 0; + term.c.state &= ~CURSOR_HIDE; break; - case 1048: - case 1049: /* XXX: no alt. screen to erase/save */ + case 1049: /* = 1047 and 1048 */ + case 1047: + if(IS_SET(MODE_ALTSCREEN)) + tclearregion(0, 0, term.col-1, term.row-1); + else + tswapscreen(); + if(escseq.arg[0] == 1047) + break; + case 1048: tcursor(CURSOR_SAVE); - tclearregion(0, 0, term.col-1, term.row-1); break; default: goto unknown; } @@ -831,6 +913,7 @@ csihandle(void) { DEFAULT(escseq.arg[0], 1); DEFAULT(escseq.arg[1], term.row); tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1); + tmoveto(0, 0); } break; case 's': /* DECSC -- Save cursor position (ANSI.SYS) */ @@ -862,12 +945,7 @@ csireset(void) { void tputtab(void) { int space = TAB - term.c.x % TAB; - - if(term.c.x + space >= term.col) - space--; - - for(; space > 0; space--) - tmovecursor(CURSOR_RIGHT); + tmoveto(term.c.x + space, term.c.y); } void @@ -915,20 +993,11 @@ tputc(char c) { case '(': term.esc |= ESC_ALTCHARSET; break; - case 'A': - tmoveto(term.c.x, term.c.y-1); - term.esc = 0; - break; - case 'B': - tmoveto(term.c.x, term.c.y+1); - term.esc = 0; - break; - case 'C': - tmoveto(term.c.x+1, term.c.y); - term.esc = 0; - break; - case 'D': /* XXX: CUP (VT100) or IND (VT52) ... */ - tmoveto(term.c.x-1, term.c.y); + case 'D': /* IND -- Linefeed */ + if(term.c.y == term.bot) + tscrollup(1); + else + tmoveto(term.c.x, term.c.y+1); term.esc = 0; break; case 'E': /* NEL -- Next line */ @@ -946,19 +1015,19 @@ tputc(char c) { treset(); term.esc = 0; break; - case '=': /* DECPAM */ + case '=': /* DECPAM -- Application keypad */ term.mode |= MODE_APPKEYPAD; term.esc = 0; break; - case '>': /* DECPNM */ + case '>': /* DECPNM -- Normal keypad */ term.mode &= ~MODE_APPKEYPAD; term.esc = 0; break; - case '7': + case '7': /* DECSC -- Save Cursor */ tcursor(CURSOR_SAVE); term.esc = 0; break; - case '8': + case '8': /* DECRC -- Restore Cursor */ tcursor(CURSOR_LOAD); term.esc = 0; break; @@ -973,7 +1042,7 @@ tputc(char c) { tputtab(); break; case '\b': - tmovecursor(CURSOR_LEFT); + tmoveto(term.c.x-1, term.c.y); break; case '\r': tmoveto(0, term.c.y); @@ -982,15 +1051,21 @@ tputc(char c) { tnewline(); break; case '\a': - xbell(); + if(!xw.hasfocus) + xseturgency(1); break; case '\033': csireset(); term.esc = ESC_START; break; default: + if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT) + tnewline(); tsetchar(c); - tmovecursor(CURSOR_RIGHT); + if(term.c.x+1 < term.col) + tmoveto(term.c.x+1, term.c.y); + else + term.c.state |= CURSOR_WRAPNEXT; break; } } @@ -1005,32 +1080,42 @@ tputs(char *s, int len) { void tresize(int col, int row) { int i; - Line *line; int minrow = MIN(row, term.row); int mincol = MIN(col, term.col); if(col < 1 || row < 1) return; - /* alloc */ - line = calloc(row, sizeof(Line)); - for(i = 0 ; i < row; i++) - line[i] = calloc(col, sizeof(Glyph)); - /* copy */ - for(i = 0 ; i < minrow; i++) - memcpy(line[i], term.line[i], mincol * sizeof(Glyph)); - /* free */ - for(i = 0; i < term.row; i++) + + /* free uneeded rows */ + for(i = row; i < term.row; i++) { free(term.line[i]); - free(term.line); - - LIMIT(term.c.x, 0, col-1); - LIMIT(term.c.y, 0, row-1); - LIMIT(term.top, 0, row-1); - LIMIT(term.bot, 0, row-1); + free(term.alt[i]); + } + + /* resize to new height */ + term.line = realloc(term.line, row * sizeof(Line)); + term.alt = realloc(term.alt, row * sizeof(Line)); + + /* resize each row to new width, zero-pad if needed */ + for(i = 0; i < minrow; i++) { + term.line[i] = realloc(term.line[i], col * sizeof(Glyph)); + term.alt[i] = realloc(term.alt[i], col * sizeof(Glyph)); + memset(term.line[i] + mincol, 0, (col - mincol) * sizeof(Glyph)); + memset(term.alt[i] + mincol, 0, (col - mincol) * sizeof(Glyph)); + } + + /* allocate any new rows */ + for(/* i == minrow */; i < row; i++) { + term.line[i] = calloc(col, sizeof(Glyph)); + term.alt [i] = calloc(col, sizeof(Glyph)); + } - term.bot = row-1; - term.line = line; + /* update terminal size */ term.col = col, term.row = row; + /* make use of the LIMIT in tmoveto */ + tmoveto(term.c.x, term.c.y); + /* reset scrolling region */ + tsetscroll(0, row-1); } void @@ -1100,10 +1185,9 @@ xhints(void) void xinit(void) { - xw.dis = XOpenDisplay(NULL); - xw.scr = XDefaultScreen(xw.dis); - if(!xw.dis) + if(!(xw.dis = XOpenDisplay(NULL))) die("Can't open display\n"); + xw.scr = XDefaultScreen(xw.dis); /* font */ if(!(dc.font = XLoadQueryFont(xw.dis, FONT)) || !(dc.bfont = XLoadQueryFont(xw.dis, BOLDFONT))) @@ -1116,9 +1200,6 @@ xinit(void) { /* colors */ xloadcols(); - term.c.attr.fg = DefaultFG; - term.c.attr.bg = DefaultBG; - term.c.attr.mode = ATTR_NULL; /* windows */ xw.h = term.row * xw.ch + 2*BORDER; xw.w = term.col * xw.cw + 2*BORDER; @@ -1131,6 +1212,12 @@ xinit(void) { xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr)); /* gc */ dc.gc = XCreateGC(xw.dis, xw.win, 0, NULL); + + /* event mask */ + XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask + | StructureNotifyMask | FocusChangeMask | PointerMotionMask + | ButtonPressMask | ButtonReleaseMask); + XMapWindow(xw.dis, xw.win); xhints(); XStoreName(xw.dis, xw.win, "st"); @@ -1163,7 +1250,7 @@ xdraws(char *s, Glyph base, int x, int y, int len) { } void -xcursor(int mode) { +xdrawcursor(void) { static int oldx = 0; static int oldy = 0; Glyph g = {' ', ATTR_NULL, DefaultBG, DefaultCS, 0}; @@ -1173,7 +1260,7 @@ xcursor(int mode) { if(term.line[term.c.y][term.c.x].state & GLYPH_SET) g.c = term.line[term.c.y][term.c.x].c; - + /* remove the old cursor */ if(term.line[oldy][oldx].state & GLYPH_SET) xdraws(&term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, oldy, 1); @@ -1181,7 +1268,7 @@ xcursor(int mode) { xclear(oldx, oldy, oldx, oldy); /* draw the new one */ - if(mode == CURSOR_DRAW) { + if(!(term.c.state & CURSOR_HIDE) && xw.hasfocus) { xdraws(&g.c, g, term.c.x, term.c.y, 1); oldx = term.c.x, oldy = term.c.y; } @@ -1208,8 +1295,7 @@ draw(int dummy) { if(term.line[y][x].state & GLYPH_SET) xdrawc(x, y, term.line[y][x]); - if(!term.hidec) - xcursor(CURSOR_DRAW); + xdrawcursor(); XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER); XFlush(xw.dis); } @@ -1221,27 +1307,33 @@ draw(int redraw_all) { int i, x, y, ox; Glyph base, new; char buf[DRAW_BUF_SIZ]; - + XSetForeground(xw.dis, dc.gc, dc.col[DefaultBG]); - XFillRectangle(xw.dis, xw.buf, dc.gc, 0, 0, xw.w, xw.h); + XFillRectangle(xw.dis, xw.buf, dc.gc, 0, 0, xw.bufw, xw.bufh); for(y = 0; y < term.row; y++) { base = term.line[y][0]; i = ox = 0; for(x = 0; x < term.col; x++) { new = term.line[y][x]; - if(!ATTRCMP(base, new) && i < DRAW_BUF_SIZ) - buf[i++] = new.c; - else { + if(sel.bx!=-1 && new.c && selected(x, y)) + new.mode ^= ATTR_REVERSE; + if(i > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) || + i >= DRAW_BUF_SIZ)) { xdraws(buf, base, ox, y, i); - buf[0] = new.c; - i = 1; - ox = x; - base = new; + i = 0; + } + if(new.state & GLYPH_SET) { + if(i == 0) { + ox = x; + base = new; + } + buf[i++] = new.c; } } - xdraws(buf, base, ox, y, i); + if(i > 0) + xdraws(buf, base, ox, y, i); } - xcursor(term.hidec ? CURSOR_HIDE : CURSOR_DRAW); + xdrawcursor(); XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER); XFlush(xw.dis); } @@ -1253,6 +1345,21 @@ expose(XEvent *ev) { draw(SCREEN_REDRAW); } +void +xseturgency(int add) { + XWMHints *h = XGetWMHints(xw.dis, xw.win); + h->flags = add ? (h->flags | XUrgencyHint) : (h->flags & ~XUrgencyHint); + XSetWMHints(xw.dis, xw.win, h); + XFree(h); +} + +void +focus(XEvent *ev) { + if((xw.hasfocus = ev->type == FocusIn)) + xseturgency(0); + draw(SCREEN_UPDATE); +} + char* kmap(KeySym k) { int i; @@ -1289,12 +1396,12 @@ kpress(XEvent *ev) { case XK_Down: case XK_Left: case XK_Right: - sprintf(buf, "\033%c%c", term.mode & MODE_APPKEYPAD ? 'O' : '[', "DACB"[ksym - XK_Left]); + sprintf(buf, "\033%c%c", IS_SET(MODE_APPKEYPAD) ? 'O' : '[', "DACB"[ksym - XK_Left]); ttywrite(buf, 3); break; case XK_Insert: if(shift) - draw(1), puts("draw!")/* XXX: paste X clipboard */; + selpaste(), draw(1); break; default: fprintf(stderr, "errkey: %d\n", (int)ksym); @@ -1317,6 +1424,8 @@ resize(XEvent *e) { row = xw.bufh / xw.ch; tresize(col, row); ttyresize(col, row); + xw.bufh = MAX(1, xw.bufh); + xw.bufw = MAX(1, xw.bufw); XFreePixmap(xw.dis, xw.buf); xw.buf = XCreatePixmap(xw.dis, xw.win, xw.bufw, xw.bufh, XDefaultDepth(xw.dis, xw.scr)); draw(SCREEN_REDRAW); @@ -1328,15 +1437,11 @@ run(void) { fd_set rfd; int xfd = XConnectionNumber(xw.dis); - running = 1; - XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNotifyMask); - XResizeWindow(xw.dis, xw.win, xw.w, xw.h); /* XXX: fix resize bug in wmii (?) */ - - while(running) { + for(;;) { FD_ZERO(&rfd); FD_SET(cmdfd, &rfd); FD_SET(xfd, &rfd); - if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL) == -1) { + if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, NULL) < 0) { if(errno == EINTR) continue; die("select failed: %s\n", SERRNO); @@ -1356,13 +1461,14 @@ run(void) { int main(int argc, char *argv[]) { if(argc == 2 && !strncmp("-v", argv[1], 3)) - die("st-" VERSION ", © 2009 st engineers\n"); + die("st-" VERSION ", (c) 2010 st engineers\n"); else if(argc != 1) die("usage: st [-v]\n"); setlocale(LC_CTYPE, ""); tnew(80, 24); ttynew(); xinit(); + selinit(); run(); return 0; }