X-Git-Url: https://git.xinqibao.xyz/st.git/blobdiff_plain/aa35bbd7a16c6c210a7574a8c45bbe939d5b2922..74962bf56636e608f0ee35f2076bc6b48923119d:/st.c

diff --git a/st.c b/st.c
index 124c047..9079834 100644
--- a/st.c
+++ b/st.c
@@ -70,8 +70,9 @@ char *argv0;
 #define LEN(a)     (sizeof(a) / sizeof(a)[0])
 #define DEFAULT(a, b)     (a) = (a) ? (a) : (b)
 #define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (b))
-#define ISCONTROLC0(c) (BETWEEN((uchar) (c), 0, 0x1f))
-#define ISCONTROLC1(c) (BETWEEN((uchar) (c), 0x80, 0x9f))
+#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f))
+#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
+#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
 #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)) != 0)
@@ -393,6 +394,7 @@ static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 static void techo(char *, int);
 static bool tcontrolcode(uchar );
+static void tdectest(char );
 static int32_t tdefcolor(int *, int *, int);
 static void tselcs(void);
 static void tdeftran(char);
@@ -402,7 +404,6 @@ static void ttyread(void);
 static void ttyresize(void);
 static void ttysend(char *, size_t);
 static void ttywrite(const char *, size_t);
-static inline bool iscontrol(char);
 
 static void xdraws(char *, Glyph, int, int, int, int);
 static void xhints(void);
@@ -448,6 +449,8 @@ static char *getsel(void);
 static void selcopy(void);
 static void selscroll(int, int);
 static void selsnap(int, int *, int *, int);
+static void getbuttoninfo(XEvent *);
+static void mousereport(XEvent *);
 
 static size_t utf8decode(char *, long *, size_t);
 static long utf8decodebyte(char, size_t *);
@@ -461,6 +464,8 @@ static void *xmalloc(size_t);
 static void *xrealloc(void *, size_t);
 static char *xstrdup(char *);
 
+static void usage(void);
+
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
 	[ClientMessage] = cmessage,
@@ -917,60 +922,59 @@ getsel(void) {
 	int x, y, bufsize, size, i, ex;
 	Glyph *gp, *last;
 
-	if(sel.ob.x == -1) {
-		str = NULL;
-	} else {
-		bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
-		ptr = str = xmalloc(bufsize);
+	if(sel.ob.x == -1)
+		return NULL;
 
-		/* append every set & selected glyph to the selection */
-		for(y = sel.nb.y; y < sel.ne.y + 1; y++) {
-			gp = &term.line[y][0];
-			last = &gp[term.col-1];
+	bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ;
+	ptr = str = xmalloc(bufsize);
 
-			while(last >= gp && !(selected(last - gp, y) &&
-			                      strcmp(last->c, " ") != 0)) {
-				--last;
-			}
+	/* append every set & selected glyph to the selection */
+	for(y = sel.nb.y; y < sel.ne.y + 1; y++) {
+		gp = &term.line[y][0];
+		last = &gp[term.col-1];
 
-			for(x = 0; gp <= last; x++, ++gp) {
-				if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))
-					continue;
+		while(last >= gp && !(selected(last - gp, y) &&
+				      strcmp(last->c, " ") != 0)) {
+			--last;
+		}
 
-				size = utf8len(gp->c);
-				memcpy(ptr, gp->c, size);
-				ptr += size;
-			}
+		for(x = 0; gp <= last; x++, ++gp) {
+			if(!selected(x, y) || (gp->mode & ATTR_WDUMMY))
+				continue;
 
-			/*
-			 * Copy and pasting of line endings is inconsistent
-			 * in the inconsistent terminal and GUI world.
-			 * The best solution seems like to produce '\n' when
-			 * something is copied from st and convert '\n' to
-			 * '\r', when something to be pasted is received by
-			 * st.
-			 * FIXME: Fix the computer world.
-			 */
-			if(y < sel.ne.y && x > 0 && !((gp-1)->mode & ATTR_WRAP))
-				*ptr++ = '\n';
+			size = utf8len(gp->c);
+			memcpy(ptr, gp->c, size);
+			ptr += size;
+		}
 
-			/*
-			 * If the last selected line expands in the selection
-			 * after the visible text '\n' is appended.
-			 */
-			if(y == sel.ne.y) {
-				i = term.col;
-				while(--i > 0 && term.line[y][i].c[0] == ' ')
-					/* nothing */;
-				ex = sel.ne.x;
-				if(sel.nb.y == sel.ne.y && sel.ne.x < sel.nb.x)
-					ex = sel.nb.x;
-				if(i < ex)
-					*ptr++ = '\n';
-			}
+		/*
+		 * Copy and pasting of line endings is inconsistent
+		 * in the inconsistent terminal and GUI world.
+		 * The best solution seems like to produce '\n' when
+		 * something is copied from st and convert '\n' to
+		 * '\r', when something to be pasted is received by
+		 * st.
+		 * FIXME: Fix the computer world.
+		 */
+		if(y < sel.ne.y && x > 0 && !((gp-1)->mode & ATTR_WRAP))
+			*ptr++ = '\n';
+
+		/*
+		 * If the last selected line expands in the selection
+		 * after the visible text '\n' is appended.
+		 */
+		if(y == sel.ne.y) {
+			i = term.col;
+			while(--i > 0 && term.line[y][i].c[0] == ' ')
+				/* nothing */;
+			ex = sel.ne.x;
+			if(sel.nb.y == sel.ne.y && sel.ne.x < sel.nb.x)
+				ex = sel.nb.x;
+			if(i < ex)
+				*ptr++ = '\n';
 		}
-		*ptr = 0;
 	}
+	*ptr = 0;
 	return str;
 }
 
@@ -1236,15 +1240,6 @@ ttynew(void) {
 	}
 }
 
-void
-dump(char c) {
-	static int col;
-
-	fprintf(stderr, " %02x '%c' ", c, isprint(c)?c:'.');
-	if(++col % 10 == 0)
-		fprintf(stderr, "\n");
-}
-
 void
 ttyread(void) {
 	static char buf[BUFSIZ];
@@ -2086,8 +2081,8 @@ csihandle(void) {
 			len = snprintf(buf, sizeof(buf),"\033[%i;%iR",
 					term.c.y+1, term.c.x+1);
 			ttywrite(buf, len);
-			break;
 		}
+		break;
 	case 'r': /* DECSTBM -- Set Scrolling Region */
 		if(csiescseq.priv) {
 			goto unknown;
@@ -2300,17 +2295,12 @@ tputtab(int n) {
 	tmoveto(x, term.c.y);
 }
 
-static inline bool
-iscontrol(char c) {
-	return ISCONTROLC0(c) || ISCONTROLC1(c);
-}
-
 void
 techo(char *buf, int len) {
 	for(; len > 0; buf++, len--) {
 		char c = *buf;
 
-		if(iscontrol(c)) { /* control code */
+		if(ISCONTROL(c)) { /* control code */
 			if(c & 0x80) {
 				c &= 0x7f;
 				tputc("^", 1);
@@ -2430,25 +2420,40 @@ tcontrolcode(uchar ascii) {
 	return 1;
 }
 
+void
+tdectest(char c) {
+	static char E[UTF_SIZ] = "E";
+	int x, y;
+
+	if(c == '8') { /* DEC screen alignment test. */
+		for(x = 0; x < term.col; ++x) {
+			for(y = 0; y < term.row; ++y)
+				tsetchar(E, &term.c.attr, x, y);
+		}
+	}
+}
+
 void
 tputc(char *c, int len) {
 	uchar ascii;
 	bool control;
 	long unicodep;
 	int width;
+	Glyph *gp;
 
 	if(len == 1) {
 		width = 1;
-		ascii = *c;
+		unicodep = ascii = *c;
 	} else {
 		utf8decode(c, &unicodep, UTF_SIZ);
 		width = wcwidth(unicodep);
+		control = ISCONTROLC1(unicodep);
 		ascii = unicodep;
 	}
 
-	control = iscontrol(ascii) && width == 1;
 	if(IS_SET(MODE_PRINT))
 		tprinter(c, len);
+	control = ISCONTROL(unicodep);
 
 	/*
 	 * STR sequence must be checked before anything else
@@ -2460,7 +2465,7 @@ tputc(char *c, int len) {
 		if(width == 1 &&
 		   (ascii == '\a' || ascii == 030 ||
 		    ascii == 032  || ascii == 033 ||
-		    ISCONTROLC1(ascii))) {
+		    ISCONTROLC1(unicodep))) {
 			term.esc &= ~ESC_STR;
 			term.esc |= ESC_STR_END;
 		} else if(strescseq.len + len < sizeof(strescseq.buf) - 1) {
@@ -2503,29 +2508,20 @@ tputc(char *c, int len) {
 				csiparse();
 				csihandle();
 			}
+			return;
 		} else if(term.esc & ESC_ALTCHARSET) {
 			tdeftran(ascii);
 			tselcs();
-			term.esc = 0;
 		} else if(term.esc & ESC_TEST) {
-			if(ascii == '8') { /* DEC screen alignment test. */
-				char E[UTF_SIZ] = "E";
-				int x, y;
-
-				for(x = 0; x < term.col; ++x) {
-					for(y = 0; y < term.row; ++y)
-						tsetchar(E, &term.c.attr, x, y);
-				}
-			}
-			term.esc = 0;
+			tdectest(ascii);
 		} else {
 			switch(ascii) {
 			case '[':
 				term.esc |= ESC_CSI;
-				break;
+				return;
 			case '#':
 				term.esc |= ESC_TEST;
-				break;
+				return;
 			case 'P': /* DCS -- Device Control String */
 			case '_': /* APC -- Application Program Command */
 			case '^': /* PM -- Privacy Message */
@@ -2534,29 +2530,26 @@ tputc(char *c, int len) {
 				strreset();
 				strescseq.type = ascii;
 				term.esc |= ESC_STR;
-				break;
+				return;
 			case '(': /* set primary charset G0 */
 			case ')': /* set secondary charset G1 */
 			case '*': /* set tertiary charset G2 */
 			case '+': /* set quaternary charset G3 */
 				term.icharset = ascii - '(';
 				term.esc |= ESC_ALTCHARSET;
-				break;
+				return;
 			case 'D': /* IND -- Linefeed */
 				if(term.c.y == term.bot) {
 					tscrollup(term.top, 1);
 				} else {
 					tmoveto(term.c.x, term.c.y+1);
 				}
-				term.esc = 0;
 				break;
 			case 'E': /* NEL -- Next line */
 				tnewline(1); /* always go to first col */
-				term.esc = 0;
 				break;
 			case 'H': /* HTS -- Horizontal tab stop */
 				term.tabs[term.c.x] = 1;
-				term.esc = 0;
 				break;
 			case 'M': /* RI -- Reverse index */
 				if(term.c.y == term.top) {
@@ -2564,46 +2557,38 @@ tputc(char *c, int len) {
 				} else {
 					tmoveto(term.c.x, term.c.y-1);
 				}
-				term.esc = 0;
 				break;
 			case 'Z': /* DECID -- Identify Terminal */
 				ttywrite(VT102ID, sizeof(VT102ID) - 1);
-				term.esc = 0;
 				break;
 			case 'c': /* RIS -- Reset to inital state */
 				treset();
-				term.esc = 0;
 				xresettitle();
 				xloadcols();
 				break;
 			case '=': /* DECPAM -- Application keypad */
 				term.mode |= MODE_APPKEYPAD;
-				term.esc = 0;
 				break;
 			case '>': /* DECPNM -- Normal keypad */
 				term.mode &= ~MODE_APPKEYPAD;
-				term.esc = 0;
 				break;
 			case '7': /* DECSC -- Save Cursor */
 				tcursor(CURSOR_SAVE);
-				term.esc = 0;
 				break;
 			case '8': /* DECRC -- Restore Cursor */
 				tcursor(CURSOR_LOAD);
-				term.esc = 0;
 				break;
 			case '\\': /* ST -- String Terminator */
 				if(term.esc & ESC_STR_END)
 					strhandle();
-				term.esc = 0;
 				break;
 			default:
 				fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
 					(uchar) ascii, isprint(ascii)? ascii:'.');
-				term.esc = 0;
 				break;
 			}
 		}
+		term.esc = 0;
 		/*
 		 * All characters which form part of a sequence are not
 		 * printed
@@ -2617,16 +2602,15 @@ tputc(char *c, int len) {
 		return;
 	if(sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
 		selclear(NULL);
+
+	gp = &term.line[term.c.y][term.c.x];
 	if(IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
-		term.line[term.c.y][term.c.x].mode |= ATTR_WRAP;
+		gp->mode |= ATTR_WRAP;
 		tnewline(1);
 	}
 
-	if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col) {
-		memmove(&term.line[term.c.y][term.c.x+1],
-			&term.line[term.c.y][term.c.x],
-			(term.col - term.c.x - 1) * sizeof(Glyph));
-	}
+	if(IS_SET(MODE_INSERT) && term.c.x+1 < term.col)
+		memmove(gp+1, gp, (term.col - term.c.x - 1) * sizeof(Glyph));
 
 	if(term.c.x+width > term.col)
 		tnewline(1);
@@ -2634,10 +2618,10 @@ tputc(char *c, int len) {
 	tsetchar(c, &term.c.attr, term.c.x, term.c.y);
 
 	if(width == 2) {
-		term.line[term.c.y][term.c.x].mode |= ATTR_WIDE;
+		gp->mode |= ATTR_WIDE;
 		if(term.c.x+1 < term.col) {
-			term.line[term.c.y][term.c.x+1].c[0] = '\0';
-			term.line[term.c.y][term.c.x+1].mode = ATTR_WDUMMY;
+			gp[1].c[0] = '\0';
+			gp[1].mode = ATTR_WDUMMY;
 		}
 	}
 	if(term.c.x+width < term.col) {
@@ -3501,12 +3485,9 @@ drawregion(int x1, int y1, int x2, int y2) {
 	int ic, ib, x, y, ox, sl;
 	Glyph base, new;
 	char buf[DRAW_BUF_SIZ];
-	bool ena_sel = sel.ob.x != -1;
+	bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 	long unicodep;
 
-	if(sel.alt != IS_SET(MODE_ALTSCREEN))
-		ena_sel = 0;
-
 	if(!(xw.state & WIN_VISIBLE))
 		return;
 
@@ -3583,7 +3564,7 @@ void
 xseturgency(int add) {
 	XWMHints *h = XGetWMHints(xw.dpy, xw.win);
 
-	h->flags = add ? (h->flags | XUrgencyHint) : (h->flags & ~XUrgencyHint);
+	MODBIT(h->flags, add, XUrgencyHint);
 	XSetWMHints(xw.dpy, xw.win, h);
 	XFree(h);
 }