X-Git-Url: https://git.xinqibao.xyz/st.git/blobdiff_plain/3bb900cd6c1c7a5364bd79bce63fdd8711bc878b..cfc7acdfd923924ae150a32061fb95987697b159:/x.c

diff --git a/x.c b/x.c
index a332ac9..a7f619e 100644
--- a/x.c
+++ b/x.c
@@ -44,6 +44,11 @@ typedef struct {
 	signed char crlf;      /* crlf mode          */
 } Key;
 
+/* X modifiers */
+#define XK_ANY_MOD    UINT_MAX
+#define XK_NO_MOD     0
+#define XK_SWITCH_MOD (1<<13)
+
 /* function definitions used in config.h */
 static void clipcopy(const Arg *);
 static void clippaste(const Arg *);
@@ -89,6 +94,9 @@ typedef struct {
 
 typedef struct {
 	Atom xtarget;
+	char *primary, *clipboard;
+	struct timespec tclick1;
+	struct timespec tclick2;
 } XSelection;
 
 /* Font structure */
@@ -149,7 +157,7 @@ static void selnotify(XEvent *);
 static void selclear_(XEvent *);
 static void selrequest(XEvent *);
 static void setsel(char *, Time);
-static void getbuttoninfo(XEvent *);
+static void mousesel(XEvent *, int);
 static void mousereport(XEvent *);
 static char *kmap(KeySym, uint);
 static int match(uint, uint);
@@ -229,11 +237,11 @@ clipcopy(const Arg *dummy)
 {
 	Atom clipboard;
 
-	if (sel.clipboard != NULL)
-		free(sel.clipboard);
+	if (xsel.clipboard != NULL)
+		free(xsel.clipboard);
 
-	if (sel.primary != NULL) {
-		sel.clipboard = xstrdup(sel.primary);
+	if (xsel.primary != NULL) {
+		xsel.clipboard = xstrdup(xsel.primary);
 		clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
 		XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
 	}
@@ -271,7 +279,6 @@ zoomabs(const Arg *arg)
 	xunloadfonts();
 	xloadfonts(usedfont, arg->f);
 	cresize(0, 0);
-	ttyresize(win.tw, win.th);
 	redraw();
 	xhints();
 }
@@ -306,24 +313,20 @@ y2row(int y)
 }
 
 void
-getbuttoninfo(XEvent *e)
+mousesel(XEvent *e, int done)
 {
-	int type;
+	int type, seltype = SEL_REGULAR;
 	uint state = e->xbutton.state & ~(Button1Mask | forceselmod);
 
-	sel.alt = IS_SET(MODE_ALTSCREEN);
-
-	sel.oe.x = x2col(e->xbutton.x);
-	sel.oe.y = y2row(e->xbutton.y);
-	selnormalize();
-
-	sel.type = SEL_REGULAR;
 	for (type = 1; type < LEN(selmasks); ++type) {
 		if (match(selmasks[type], state)) {
-			sel.type = type;
+			seltype = type;
 			break;
 		}
 	}
+	selextend(x2col(e->xbutton.x), y2row(e->xbutton.y), seltype, done);
+	if (done)
+		setsel(getsel(), e->xbutton.time);
 }
 
 void
@@ -395,6 +398,7 @@ bpress(XEvent *e)
 {
 	struct timespec now;
 	MouseShortcut *ms;
+	int snap;
 
 	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);
@@ -410,33 +414,22 @@ bpress(XEvent *e)
 	}
 
 	if (e->xbutton.button == Button1) {
-		clock_gettime(CLOCK_MONOTONIC, &now);
-
-		/* Clear previous selection, logically and visually. */
-		selclear_(NULL);
-		sel.mode = SEL_EMPTY;
-		sel.type = SEL_REGULAR;
-		sel.oe.x = sel.ob.x = x2col(e->xbutton.x);
-		sel.oe.y = sel.ob.y = y2row(e->xbutton.y);
-
 		/*
 		 * If the user clicks below predefined timeouts specific
 		 * snapping behaviour is exposed.
 		 */
-		if (TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) {
-			sel.snap = SNAP_LINE;
-		} else if (TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) {
-			sel.snap = SNAP_WORD;
+		clock_gettime(CLOCK_MONOTONIC, &now);
+		if (TIMEDIFF(now, xsel.tclick2) <= tripleclicktimeout) {
+			snap = SNAP_LINE;
+		} else if (TIMEDIFF(now, xsel.tclick1) <= doubleclicktimeout) {
+			snap = SNAP_WORD;
 		} else {
-			sel.snap = 0;
+			snap = 0;
 		}
-		selnormalize();
+		xsel.tclick2 = xsel.tclick1;
+		xsel.tclick1 = now;
 
-		if (sel.snap != 0)
-			sel.mode = SEL_READY;
-		tsetdirt(sel.nb.y, sel.ne.y);
-		sel.tclick2 = sel.tclick1;
-		sel.tclick1 = now;
+		selstart(x2col(e->xbutton.x), y2row(e->xbutton.y), snap);
 	}
 }
 
@@ -590,9 +583,9 @@ selrequest(XEvent *e)
 		 */
 		clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
 		if (xsre->selection == XA_PRIMARY) {
-			seltext = sel.primary;
+			seltext = xsel.primary;
 		} else if (xsre->selection == clipboard) {
-			seltext = sel.clipboard;
+			seltext = xsel.clipboard;
 		} else {
 			fprintf(stderr,
 				"Unhandled clipboard selection 0x%lx\n",
@@ -616,8 +609,8 @@ selrequest(XEvent *e)
 void
 setsel(char *str, Time t)
 {
-	free(sel.primary);
-	sel.primary = str;
+	free(xsel.primary);
+	xsel.primary = str;
 
 	XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
 	if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
@@ -638,41 +631,21 @@ brelease(XEvent *e)
 		return;
 	}
 
-	if (e->xbutton.button == Button2) {
+	if (e->xbutton.button == Button2)
 		selpaste(NULL);
-	} else if (e->xbutton.button == Button1) {
-		if (sel.mode == SEL_READY) {
-			getbuttoninfo(e);
-			setsel(getsel(), e->xbutton.time);
-		} else
-			selclear_(NULL);
-		sel.mode = SEL_IDLE;
-		tsetdirt(sel.nb.y, sel.ne.y);
-	}
+	else if (e->xbutton.button == Button1)
+		mousesel(e, 1);
 }
 
 void
 bmotion(XEvent *e)
 {
-	int oldey, oldex, oldsby, oldsey;
-
 	if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
 		mousereport(e);
 		return;
 	}
 
-	if (!sel.mode)
-		return;
-
-	sel.mode = SEL_READY;
-	oldey = sel.oe.y;
-	oldex = sel.oe.x;
-	oldsby = sel.nb.y;
-	oldsey = sel.ne.y;
-	getbuttoninfo(e);
-
-	if (oldey != sel.oe.y || oldex != sel.oe.x)
-		tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
+	mousesel(e, 0);
 }
 
 void
@@ -690,6 +663,7 @@ cresize(int width, int height)
 
 	tresize(col, row);
 	xresize(col, row);
+	ttyresize(win.tw, win.th);
 }
 
 void
@@ -1122,6 +1096,10 @@ xinit(void)
 	xhints();
 	XSync(xw.dpy, False);
 
+	clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1);
+	clock_gettime(CLOCK_MONOTONIC, &xsel.tclick2);
+	xsel.primary = NULL;
+	xsel.clipboard = NULL;
 	xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
 	if (xsel.xtarget == None)
 		xsel.xtarget = XA_STRING;
@@ -1413,7 +1391,6 @@ xdrawcursor(void)
 	static int oldx = 0, oldy = 0;
 	int curx;
 	Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og;
-	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 	Color drawcol;
 
 	LIMIT(oldx, 0, term.col-1);
@@ -1429,7 +1406,7 @@ xdrawcursor(void)
 
 	/* remove the old cursor */
 	og = term.line[oldy][oldx];
-	if (ena_sel && selected(oldx, oldy))
+	if (selected(oldx, oldy))
 		og.mode ^= ATTR_REVERSE;
 	xdrawglyph(og, oldx, oldy);
 
@@ -1443,7 +1420,7 @@ xdrawcursor(void)
 	if (IS_SET(MODE_REVERSE)) {
 		g.mode |= ATTR_REVERSE;
 		g.bg = defaultfg;
-		if (ena_sel && selected(term.c.x, term.c.y)) {
+		if (selected(term.c.x, term.c.y)) {
 			drawcol = dc.col[defaultcs];
 			g.fg = defaultrcs;
 		} else {
@@ -1451,7 +1428,7 @@ xdrawcursor(void)
 			g.fg = defaultcs;
 		}
 	} else {
-		if (ena_sel && selected(term.c.x, term.c.y)) {
+		if (selected(term.c.x, term.c.y)) {
 			drawcol = dc.col[defaultrcs];
 			g.fg = defaultfg;
 			g.bg = defaultrcs;
@@ -1550,7 +1527,6 @@ drawregion(int x1, int y1, int x2, int y2)
 	int i, x, y, ox, numspecs;
 	Glyph base, new;
 	XftGlyphFontSpec *specs;
-	int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
 
 	if (!(win.state & WIN_VISIBLE))
 		return;
@@ -1569,7 +1545,7 @@ drawregion(int x1, int y1, int x2, int y2)
 			new = term.line[y][x];
 			if (new.mode == ATTR_WDUMMY)
 				continue;
-			if (ena_sel && selected(x, y))
+			if (selected(x, y))
 				new.mode ^= ATTR_REVERSE;
 			if (i > 0 && ATTRCMP(base, new)) {
 				xdrawglyphfontspecs(specs, base, i, ox, y);
@@ -1789,7 +1765,6 @@ resize(XEvent *e)
 		return;
 
 	cresize(e->xconfigure.width, e->xconfigure.height);
-	ttyresize(win.tw, win.th);
 }
 
 void
@@ -1818,9 +1793,8 @@ run(void)
 		}
 	} while (ev.type != MapNotify);
 
-	cresize(w, h);
 	ttynew(opt_line, opt_io, opt_cmd);
-	ttyresize(win.tw, win.th);
+	cresize(w, h);
 
 	clock_gettime(CLOCK_MONOTONIC, &last);
 	lastblink = last;