X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=st.c;h=0b21404ab8618114ce8b7eaa02b5644aefef47ec;hb=596bb133a55a6aba13b55795a9a38e29fcf1b38b;hp=af3ec6d14b1bc18c746f6cf225b4c4b5b943c37d;hpb=bef87acd0d0e22ba4689be6f1c39ce2d90812317;p=st.git diff --git a/st.c b/st.c index af3ec6d..0b21404 100644 --- a/st.c +++ b/st.c @@ -20,11 +20,11 @@ #include #include -#if defined(LINUX) +#if defined(__linux) #include -#elif defined(OPENBSD) || defined(NETBSD) +#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 */ @@ -156,6 +157,7 @@ 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); @@ -175,6 +177,9 @@ static char* kmap(KeySym); static void kpress(XEvent *); static void resize(XEvent *); static void focus(XEvent *); +static void brelease(XEvent *e); +static void bpress(XEvent *e); +static void bmotion(XEvent *e); static void (*handler[LASTEvent])(XEvent *) = { @@ -183,6 +188,9 @@ static void (*handler[LASTEvent])(XEvent *) = { [ConfigureNotify] = resize, [FocusIn] = focus, [FocusOut] = focus, + [MotionNotify] = bmotion, + [ButtonPress] = bpress, + [ButtonRelease] = brelease, }; /* Globals */ @@ -193,6 +201,103 @@ static CSIEscape escseq; static int cmdfd; static pid_t pid; +/* selection */ +// TODO: use X11 clipboard +static int selmode = 0; +static int selbx = -1, selby; +static int selex, seley; +int sb[2], se[2]; +static const char *clipboard = NULL; + +static inline int selected(int x, int y) { + if ((seley==y && selby==y)) { + int bx = MIN(selbx, selex); + int ex = MAX(selbx, selex); + return (x>=bx && x<=ex); + } + return (((y>sb[1] && y=sb[0] && (x<=se[0] || sb[1]!=se[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; + sb[0] = selbyxbutton.x/xw.cw; + seley = selby = e->xbutton.y/xw.ch; +} + +static char *getseltext() { + char *str, *ptr; + int ls, x, y, sz; + if(selbx==-1) + return NULL; + sz = ((xw.w/xw.ch) * (se[1]-sb[1]+2)); + ptr = str = malloc (sz); + for(y = 0; y < term.row; y++) { + for(x = 0; x < term.col; x++) { + if(term.line[y][x].c && (ls=selected(x, y))) { + *ptr = term.line[y][x].c; + ptr++; + } + } + if (ls) { + *ptr = '\n'; + ptr++; + } + } + *ptr = 0; + return str; +} + +static void clipboard_copy(const char *str) { + free((void *)clipboard); + clipboard = str; +} + +static void clipboard_paste() { + if(clipboard) + ttywrite(clipboard, strlen(clipboard)); +} + +// TODO: doubleclick to select word +static void brelease(XEvent *e) { + int b; + selmode = 0; + getbuttoninfo(e, &b, &selex, &seley); + if(b==4) + tscrollup(1); + else + if(b==5) + tscrolldown(1); + else + if(selbx==selex && selby==seley) { + selbx = -1; + if(b==2) + clipboard_paste(); + } else { + if(b==1) + clipboard_copy(getseltext()); + } + draw(1); +} + +static void bmotion(XEvent *e) { + if (selmode) { + getbuttoninfo(e, NULL, &selex, &seley); + draw(1); + } +} + #ifdef DEBUG void tdump(void) { @@ -226,7 +331,7 @@ die(const char *errstr, ...) { void execsh(void) { char *args[3] = {getenv("SHELL"), "-i", NULL}; - DEFAULT(args[0], "/bin/sh"); /* if getenv() failed */ + DEFAULT(args[0], SHELL); /* if getenv() failed */ putenv("TERM=" TNAME); execvp(args[0], args); } @@ -337,13 +442,24 @@ 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; Line temp; @@ -712,10 +828,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; @@ -761,10 +888,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; } @@ -889,19 +1027,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; @@ -961,21 +1099,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; @@ -1129,7 +1274,7 @@ xdrawcursor(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; } @@ -1168,7 +1313,7 @@ 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.bufw, xw.bufh); for(y = 0; y < term.row; y++) { @@ -1176,8 +1321,10 @@ draw(int redraw_all) { i = ox = 0; for(x = 0; x < term.col; x++) { new = term.line[y][x]; + if(selbx!=-1 && new.c && selected(x, y)) + new.mode = ATTR_REVERSE; if(i > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) || - i >= DRAW_BUF_SIZ)) { + i >= DRAW_BUF_SIZ)) { xdraws(buf, base, ox, y, i); i = 0; } @@ -1216,6 +1363,7 @@ void focus(XEvent *ev) { if((xw.hasfocus = ev->type == FocusIn)) xseturgency(0); + draw(SCREEN_UPDATE); } char* @@ -1292,7 +1440,7 @@ run(void) { XEvent ev; fd_set rfd; int xfd = XConnectionNumber(xw.dis); - long mask = ExposureMask | KeyPressMask | StructureNotifyMask | FocusChangeMask; + long mask = ExposureMask | KeyPressMask | StructureNotifyMask | FocusChangeMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask; XSelectInput(xw.dis, xw.win, mask); XResizeWindow(xw.dis, xw.win, xw.w, xw.h); /* XXX: fix resize bug in wmii (?) */