selection clicks, shift+arrow keys, fast(er) redraw, key mask in config.h (thx Magnus Leuthner)
This commit is contained in:
		
							
								
								
									
										45
									
								
								config.def.h
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								config.def.h
									
									
									
									
									
								
							| @@ -31,27 +31,28 @@ static const char *colorname[] = { | ||||
| #define DefaultBG 0 | ||||
| #define DefaultCS 1 | ||||
|  | ||||
| /* Special keys */ | ||||
| /* Special keys (change & recompile st.info accordingly) */ | ||||
| /*    key,        mask,  output */ | ||||
| static Key key[] = { | ||||
| 	{ XK_BackSpace, "\177" }, | ||||
| 	{ XK_Insert,    "\033[2~" }, | ||||
| 	{ XK_Delete,    "\033[3~" }, | ||||
| 	{ XK_Home,      "\033[1~" }, | ||||
| 	{ XK_End,       "\033[4~" }, | ||||
| 	{ XK_Prior,     "\033[5~" }, | ||||
| 	{ XK_Next,      "\033[6~" }, | ||||
| 	{ XK_F1,        "\033OP"   }, | ||||
| 	{ XK_F2,        "\033OQ"   }, | ||||
| 	{ XK_F3,        "\033OR"   }, | ||||
| 	{ XK_F4,        "\033OS"   }, | ||||
| 	{ XK_F5,        "\033[15~" }, | ||||
| 	{ XK_F6,        "\033[17~" }, | ||||
| 	{ XK_F7,        "\033[18~" }, | ||||
| 	{ XK_F8,        "\033[19~" }, | ||||
| 	{ XK_F9,        "\033[20~" }, | ||||
| 	{ XK_F10,       "\033[21~" }, | ||||
| 	{ XK_F11,       "\033[23~" }, | ||||
| 	{ XK_F12,       "\033[24~" }, | ||||
| 	{ XK_BackSpace, 0, "\177" }, | ||||
| 	{ XK_Insert,    0, "\033[2~" }, | ||||
| 	{ XK_Delete,    0, "\033[3~" }, | ||||
| 	{ XK_Home,      0, "\033[1~" }, | ||||
| 	{ XK_End,       0, "\033[4~" }, | ||||
| 	{ XK_Prior,     0, "\033[5~" }, | ||||
| 	{ XK_Next,      0, "\033[6~" }, | ||||
| 	{ XK_F1,        0, "\033OP"   }, | ||||
| 	{ XK_F2,        0, "\033OQ"   }, | ||||
| 	{ XK_F3,        0, "\033OR"   }, | ||||
| 	{ XK_F4,        0, "\033OS"   }, | ||||
| 	{ XK_F5,        0, "\033[15~" }, | ||||
| 	{ XK_F6,        0, "\033[17~" }, | ||||
| 	{ XK_F7,        0, "\033[18~" }, | ||||
| 	{ XK_F8,        0, "\033[19~" }, | ||||
| 	{ XK_F9,        0, "\033[20~" }, | ||||
| 	{ XK_F10,       0, "\033[21~" }, | ||||
| 	{ XK_F11,       0, "\033[23~" }, | ||||
| 	{ XK_F12,       0, "\033[24~" }, | ||||
| }; | ||||
|  | ||||
| /* Line drawing characters (sometime specific to each font...) */ | ||||
| @@ -61,3 +62,7 @@ static char gfx[] = { | ||||
| 	['i'] = '#', | ||||
| 	[255] = 0, | ||||
| }; | ||||
|  | ||||
| /* double-click timeout (in milliseconds) between clicks for selection */ | ||||
| #define DOUBLECLICK_TIMEOUT 300 | ||||
| #define TRIPLECLICK_TIMEOUT (2*DOUBLECLICK_TIMEOUT) | ||||
|   | ||||
							
								
								
									
										112
									
								
								st.c
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								st.c
									
									
									
									
									
								
							| @@ -22,6 +22,9 @@ | ||||
| #include <X11/cursorfont.h> | ||||
| #include <X11/keysym.h> | ||||
|  | ||||
| #include <sys/time.h> | ||||
| #include <time.h> | ||||
|  | ||||
| #if   defined(__linux) | ||||
|  #include <pty.h> | ||||
| #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) | ||||
| @@ -50,6 +53,7 @@ | ||||
| #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)) | ||||
| #define TIMEDIFFERENCE(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000) | ||||
|  | ||||
| /* 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 }; | ||||
| @@ -60,7 +64,6 @@ enum { GLYPH_SET=1, GLYPH_DIRTY=2 }; | ||||
| enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4, MODE_ALTSCREEN=8, | ||||
|        MODE_CRLF=16 }; | ||||
| enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 }; | ||||
| enum { SCREEN_UPDATE, SCREEN_REDRAW }; | ||||
| enum { WIN_VISIBLE=1, WIN_REDRAW=2, WIN_FOCUSED=4 }; | ||||
|  | ||||
| #undef B0 | ||||
| @@ -129,6 +132,7 @@ typedef struct { | ||||
|  | ||||
| typedef struct { | ||||
| 	KeySym k; | ||||
| 	unsigned int mask; | ||||
| 	char s[ESC_BUF_SIZ]; | ||||
| } Key; | ||||
|  | ||||
| @@ -153,12 +157,15 @@ typedef struct { | ||||
| 	struct {int x, y;} b, e; | ||||
| 	char *clip; | ||||
| 	Atom xtarget; | ||||
| 	struct timeval tclick1; | ||||
| 	struct timeval tclick2; | ||||
| } Selection; | ||||
|  | ||||
| #include "config.h" | ||||
|  | ||||
| static void die(const char *errstr, ...); | ||||
| static void draw(int); | ||||
| static void draw(); | ||||
| static void drawregion(int, int, int, int); | ||||
| static void execsh(void); | ||||
| static void sigchld(int); | ||||
| static void run(void); | ||||
| @@ -206,7 +213,7 @@ static void xresize(int, int); | ||||
| static void expose(XEvent *); | ||||
| static void visibility(XEvent *); | ||||
| static void unmap(XEvent *); | ||||
| static char* kmap(KeySym); | ||||
| static char* kmap(KeySym, unsigned int state); | ||||
| static void kpress(XEvent *); | ||||
| static void resize(XEvent *); | ||||
| static void focus(XEvent *); | ||||
| @@ -219,7 +226,7 @@ static void selrequest(XEvent *); | ||||
| static void selinit(void); | ||||
| static inline int selected(int, int); | ||||
| static void selcopy(void); | ||||
| static void selpaste(void); | ||||
| static void selpaste(); | ||||
|  | ||||
| static int utf8decode(char *, long *); | ||||
| static int utf8encode(long *, char *); | ||||
| @@ -368,6 +375,8 @@ utf8size(char *s) { | ||||
|  | ||||
| void | ||||
| selinit(void) { | ||||
| 	sel.tclick1.tv_sec = 0; | ||||
| 	sel.tclick1.tv_usec = 0; | ||||
| 	sel.mode = 0; | ||||
| 	sel.bx = -1; | ||||
| 	sel.clip = NULL; | ||||
| @@ -511,30 +520,63 @@ xsetsel(char *str) { | ||||
| 	XFlush(xw.dpy); | ||||
| } | ||||
|  | ||||
| /* TODO: doubleclick to select word */ | ||||
| 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) { | ||||
| 	 | ||||
| 	if(sel.bx == sel.ex && sel.by == sel.ey) { | ||||
| 		sel.bx = -1; | ||||
| 		if(b==2) | ||||
| 		if(b == 2) | ||||
| 			selpaste(); | ||||
| 	} else { | ||||
| 		if(b==1) | ||||
|  | ||||
| 		else if(b == 1) { | ||||
| 			/* double click to select word */ | ||||
| 			struct timeval now; | ||||
| 			gettimeofday(&now, NULL); | ||||
|  | ||||
| 			if(TIMEDIFFERENCE(now, sel.tclick1) <= DOUBLECLICK_TIMEOUT) { | ||||
| 				sel.bx = sel.ex; | ||||
| 				while(term.line[sel.ey][sel.bx-1].state & GLYPH_SET &&  | ||||
| 					  term.line[sel.ey][sel.bx-1].c[0] != ' ') sel.bx--; | ||||
| 				sel.b.x = sel.bx; | ||||
| 				while(term.line[sel.ey][sel.ex+1].state & GLYPH_SET &&  | ||||
| 					  term.line[sel.ey][sel.ex+1].c[0] != ' ') sel.ex++; | ||||
| 				sel.e.x = sel.ex; | ||||
| 				sel.b.y = sel.e.y = sel.ey; | ||||
| 				selcopy(); | ||||
| 			} | ||||
| 	draw(1); | ||||
|  | ||||
| 			/* triple click on the line */ | ||||
| 			if(TIMEDIFFERENCE(now, sel.tclick2) <= TRIPLECLICK_TIMEOUT) { | ||||
| 				sel.b.x = sel.bx = 0; | ||||
| 				sel.e.x = sel.ex = term.col; | ||||
| 				sel.b.y = sel.e.y = sel.ey; | ||||
| 				selcopy(); | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		if(b == 1)  | ||||
| 			selcopy(); | ||||
| 	} | ||||
| 	memcpy(&sel.tclick2, &sel.tclick1, sizeof(struct timeval)); | ||||
| 	gettimeofday(&sel.tclick1, NULL); | ||||
| 	draw(); | ||||
| } | ||||
|  | ||||
| void | ||||
| bmotion(XEvent *e) { | ||||
| 	if (sel.mode) { | ||||
| 	if(sel.mode) { | ||||
| 		int oldey = sel.ey,  | ||||
| 			oldex = sel.ex; | ||||
| 		getbuttoninfo(e, NULL, &sel.ex, &sel.ey); | ||||
| 		/* XXX: draw() can't keep up, disabled for now. | ||||
| 		   selection is visible on button release. | ||||
| 		   draw(1); */ | ||||
|  | ||||
| 		if(oldey != sel.ey || oldex != sel.ex) { | ||||
| 			int starty = MIN(oldey, sel.ey); | ||||
| 			int endy = MAX(oldey, sel.ey); | ||||
| 			drawregion(0, (starty > 0 ? starty : 0), term.col, (sel.ey < term.row ? endy+1 : term.row)); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -641,6 +683,10 @@ ttyread(void) { | ||||
|  | ||||
| void | ||||
| ttywrite(const char *s, size_t n) { | ||||
| 	{size_t nn; | ||||
| 		for(nn = 0; nn < n; nn++) | ||||
| 			dump(s[nn]); | ||||
| 	} | ||||
| 	if(write(cmdfd, s, n) == -1) | ||||
| 		die("write error on tty: %s\n", SERRNO); | ||||
| } | ||||
| @@ -1641,7 +1687,12 @@ xdrawc(int x, int y, Glyph g) { | ||||
| } | ||||
|  | ||||
| void  | ||||
| draw(int dummy) { | ||||
| drawregion(int x0, int x1, int y0, int y1) { | ||||
| 	draw(); | ||||
| } | ||||
|  | ||||
| void | ||||
| draw() { | ||||
| 	int x, y; | ||||
|  | ||||
| 	xclear(0, 0, term.col-1, term.row-1); | ||||
| @@ -1658,7 +1709,12 @@ draw(int dummy) { | ||||
| #else | ||||
| /* optimized drawing routine */ | ||||
| void  | ||||
| draw(int redraw_all) { | ||||
| draw() { | ||||
| 	drawregion(0, 0, term.col, term.row); | ||||
| } | ||||
|  | ||||
| void | ||||
| drawregion(int x1, int y1, int x2, int y2) { | ||||
| 	int ic, ib, x, y, ox, sl; | ||||
| 	Glyph base, new; | ||||
| 	char buf[DRAW_BUF_SIZ]; | ||||
| @@ -1666,13 +1722,13 @@ draw(int redraw_all) { | ||||
| 	if(!(xw.state & WIN_VISIBLE)) | ||||
| 		return; | ||||
|  | ||||
| 	xclear(0, 0, term.col-1, term.row-1); | ||||
| 	for(y = 0; y < term.row; y++) { | ||||
| 	xclear(x1, y1, x2-1, y2-1); | ||||
| 	for(y = y1; y < y2; y++) { | ||||
| 		base = term.line[y][0]; | ||||
| 		ic = ib = ox = 0; | ||||
| 		for(x = 0; x < term.col; x++) { | ||||
| 		for(x = x1; x < x2; x++) { | ||||
| 			new = term.line[y][x]; | ||||
| 			if(sel.bx!=-1 && *(new.c) && selected(x, y)) | ||||
| 			if(sel.bx != -1 && *(new.c) && selected(x, y)) | ||||
| 				new.mode ^= ATTR_REVERSE; | ||||
| 			if(ib > 0 && (!(new.state & GLYPH_SET) || ATTRCMP(base, new) || | ||||
| 					ib >= DRAW_BUF_SIZ-UTF_SIZ)) { | ||||
| @@ -1705,7 +1761,7 @@ expose(XEvent *ev) { | ||||
| 	if(xw.state & WIN_REDRAW) { | ||||
| 		if(!e->count) { | ||||
| 			xw.state &= ~WIN_REDRAW; | ||||
| 			draw(SCREEN_REDRAW); | ||||
| 			draw(); | ||||
| 		} | ||||
| 	} else | ||||
| 		XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, e->x-BORDER, e->y-BORDER, | ||||
| @@ -1742,14 +1798,14 @@ focus(XEvent *ev) { | ||||
| 		xseturgency(0); | ||||
| 	} else | ||||
| 		xw.state &= ~WIN_FOCUSED; | ||||
| 	draw(SCREEN_UPDATE); | ||||
| 	draw(); | ||||
| } | ||||
|  | ||||
| char* | ||||
| kmap(KeySym k) { | ||||
| kmap(KeySym k, unsigned int state) { | ||||
| 	int i; | ||||
| 	for(i = 0; i < LEN(key); i++) | ||||
| 		if(key[i].k == k) | ||||
| 		if(key[i].k == k && (key[i].mask == 0 || key[i].mask & state)) | ||||
| 			return (char*)key[i].s; | ||||
| 	return NULL; | ||||
| } | ||||
| @@ -1770,7 +1826,7 @@ kpress(XEvent *ev) { | ||||
| 	len = XmbLookupString(xw.xic, e, buf, sizeof(buf), &ksym, &status); | ||||
| 	 | ||||
| 	/* 1. custom keys from config.h */ | ||||
| 	if((customkey = kmap(ksym))) | ||||
| 	if((customkey = kmap(ksym, e->state))) | ||||
| 		ttywrite(customkey, strlen(customkey)); | ||||
| 	/* 2. hardcoded (overrides X lookup) */ | ||||
| 	else | ||||
| @@ -1779,7 +1835,7 @@ kpress(XEvent *ev) { | ||||
| 		case XK_Down: | ||||
| 		case XK_Left: | ||||
| 		case XK_Right: | ||||
| 			sprintf(buf, "\033%c%c", IS_SET(MODE_APPKEYPAD) ? 'O' : '[', "DACB"[ksym - XK_Left]); | ||||
| 			sprintf(buf, "\033%c%c", IS_SET(MODE_APPKEYPAD) ? 'O' : '[', (shift ? "dacb":"DACB")[ksym - XK_Left]); | ||||
| 			ttywrite(buf, 3); | ||||
| 			break; | ||||
| 		case XK_Insert: | ||||
| @@ -1817,7 +1873,7 @@ resize(XEvent *e) { | ||||
| 	if(col == term.col && row == term.row) | ||||
| 		return; | ||||
| 	if(tresize(col, row)) | ||||
| 		draw(SCREEN_REDRAW); | ||||
| 		draw(); | ||||
| 	ttyresize(col, row); | ||||
| 	xresize(col, row); | ||||
| } | ||||
| @@ -1839,7 +1895,7 @@ run(void) { | ||||
| 		} | ||||
| 		if(FD_ISSET(cmdfd, &rfd)) { | ||||
| 			ttyread(); | ||||
| 			draw(SCREEN_UPDATE);  | ||||
| 			draw();  | ||||
| 		} | ||||
| 		while(XPending(xw.dpy)) { | ||||
| 			XNextEvent(xw.dpy, &ev); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user