X-Git-Url: https://git.danieliu.xyz/?a=blobdiff_plain;f=st.c;h=fb1172a2bf625fdc22c84f63535534204926d853;hb=e1ce89f2678628b1c0e904800822a553de2817de;hp=6dcded58996e7796bb0f6e8957c6980a9a88e313;hpb=7d88cf88d05c5f5fffbe096da9fac79d7d8957f9;p=st.git diff --git a/st.c b/st.c index 6dcded5..fb1172a 100644 --- a/st.c +++ b/st.c @@ -20,11 +20,11 @@ #include #include -#if defined(LINUX) +#if defined(__linux) #include -#elif defined(OPENBSD) +#elif defined(__OpenBSD__) || defined(__NetBSD__) #include -#elif defined(FREEBSD) +#elif defined(__FreeBSD__) || defined(__DragonFly__) #include #endif @@ -50,7 +50,7 @@ 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 }; @@ -86,7 +86,8 @@ 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 */ int top; /* top scroll limit */ int bot; /* bottom scroll limit */ @@ -108,6 +109,7 @@ typedef struct { int bufh; /* pixmap height */ int ch; /* char height */ int cw; /* char width */ + int hasfocus; } XWindow; typedef struct { @@ -155,29 +157,34 @@ 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 xbell(void); static void xdraws(char *, Glyph, int, int, int); static void xhints(void); static void xclear(int, int, int, int); -static void xcursor(void); +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 (*handler[LASTEvent])(XEvent *) = { [KeyPress] = kpress, [Expose] = expose, - [ConfigureNotify] = resize + [ConfigureNotify] = resize, + [FocusIn] = focus, + [FocusOut] = focus, }; /* Globals */ @@ -187,7 +194,6 @@ static Term term; static CSIEscape escseq; static int cmdfd; static pid_t pid; -static int running; #ifdef DEBUG void @@ -227,15 +233,6 @@ execsh(void) { execvp(args[0], args); } -void -xbell(void) { - XSetForeground(xw.dis, dc.gc, dc.col[BellCol]); - XFillRectangle(xw.dis, xw.win, dc.gc, BORDER, BORDER, xw.bufw, xw.bufh); - XFlush(xw.dis); - usleep(BellTime); - draw(SCREEN_REDRAW); -} - void sigchld(int a) { int stat = 0; @@ -342,12 +339,23 @@ tnew(int col, int row) { /* set screen size */ term.row = row, term.col = col; term.line = malloc(term.row * sizeof(Line)); - for(row = 0 ; row < term.row; row++) + 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(); } +void +tswapscreen(void) { + Line* tmp = term.line; + term.line = term.alt; + term.alt = tmp; + term.mode ^= MODE_ALTSCREEN; +} + void tscrolldown (int n) { int i; @@ -717,10 +725,21 @@ csihandle(void) { case 25: term.c.state |= CURSOR_HIDE; break; - case 1048: /* XXX: no alt. screen to erase/save */ + case 1047: + if(IS_SET(MODE_ALTSCREEN)) { + tclearregion(0, 0, term.col-1, term.row-1); + tswapscreen(); + } + break; + case 1048: + tcursor(CURSOR_LOAD); + break; case 1049: tcursor(CURSOR_LOAD); - tclearregion(0, 0, term.col-1, term.row-1); + if(IS_SET(MODE_ALTSCREEN)) { + tclearregion(0, 0, term.col-1, term.row-1); + tswapscreen(); + } break; default: goto unknown; @@ -766,10 +785,21 @@ csihandle(void) { case 25: term.c.state &= ~CURSOR_HIDE; break; - case 1048: - case 1049: /* XXX: no alt. screen to erase/save */ + case 1047: + if(IS_SET(MODE_ALTSCREEN)) + tclearregion(0, 0, term.col-1, term.row-1); + else + tswapscreen(); + break; + case 1048: tcursor(CURSOR_SAVE); - tclearregion(0, 0, term.col-1, term.row-1); + break; + case 1049: + tcursor(CURSOR_SAVE); + if(IS_SET(MODE_ALTSCREEN)) + tclearregion(0, 0, term.col-1, term.row-1); + else + tswapscreen(); break; default: goto unknown; } @@ -894,19 +924,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; @@ -930,7 +960,8 @@ tputc(char c) { tnewline(); break; case '\a': - xbell(); + if(!xw.hasfocus) + xseturgency(1); break; case '\033': csireset(); @@ -965,21 +996,28 @@ tresize(int col, int row) { return; /* free uneeded rows */ - for(i = row; i < term.row; i++) + for(i = row; i < term.row; i++) { free(term.line[i]); + 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++) + for(/* i == minrow */; i < row; i++) { term.line[i] = calloc(col, sizeof(Glyph)); + term.alt [i] = calloc(col, sizeof(Glyph)); + } /* update terminal size */ term.col = col, term.row = row; @@ -1071,9 +1109,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; @@ -1118,7 +1153,7 @@ xdraws(char *s, Glyph base, int x, int y, int len) { } void -xcursor(void) { +xdrawcursor(void) { static int oldx = 0; static int oldy = 0; Glyph g = {' ', ATTR_NULL, DefaultBG, DefaultCS, 0}; @@ -1136,7 +1171,7 @@ xcursor(void) { xclear(oldx, oldy, oldx, oldy); /* draw the new one */ - if(!(term.c.state & CURSOR_HIDE)) { + 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; } @@ -1163,7 +1198,7 @@ draw(int dummy) { if(term.line[y][x].state & GLYPH_SET) xdrawc(x, y, term.line[y][x]); - xcursor(); + xdrawcursor(); XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER); XFlush(xw.dis); } @@ -1199,7 +1234,7 @@ draw(int redraw_all) { if(i > 0) xdraws(buf, base, ox, y, i); } - xcursor(); + xdrawcursor(); XCopyArea(xw.dis, xw.buf, xw.win, dc.gc, 0, 0, xw.bufw, xw.bufh, BORDER, BORDER); XFlush(xw.dis); } @@ -1211,6 +1246,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; @@ -1285,12 +1335,12 @@ run(void) { XEvent ev; fd_set rfd; int xfd = XConnectionNumber(xw.dis); + long mask = ExposureMask | KeyPressMask | StructureNotifyMask | FocusChangeMask; - running = 1; - XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNotifyMask); + XSelectInput(xw.dis, xw.win, mask); XResizeWindow(xw.dis, xw.win, xw.w, xw.h); /* XXX: fix resize bug in wmii (?) */ - while(running) { + while(1) { FD_ZERO(&rfd); FD_SET(cmdfd, &rfd); FD_SET(xfd, &rfd);