X-Git-Url: https://git.xinqibao.xyz/st.git/blobdiff_plain/cddbd6eee59104a029087c30f9ff5e7e415bc584..907cb8bfa69926616639f9a19127117b37326029:/st.c?ds=sidebyside

diff --git a/st.c b/st.c
index df8353a..72e57c8 100644
--- a/st.c
+++ b/st.c
@@ -34,15 +34,21 @@
 #endif
 
 #define USAGE \
-	"st-" VERSION ", (c) 2010-2011 st engineers\n" \
+	"st " VERSION " (c) 2010-2011 st engineers\n" \
 	"usage: st [-t title] [-c class] [-w windowid] [-v] [-e command...]\n"
 
+/* XEMBED messages */
+#define XEMBED_FOCUS_IN  4
+#define XEMBED_FOCUS_OUT 5
+
 /* Arbitrary sizes */
 #define ESC_TITLE_SIZ 256
 #define ESC_BUF_SIZ   256
 #define ESC_ARG_SIZ   16
 #define DRAW_BUF_SIZ  1024
 #define UTF_SIZ       4
+#define XK_NO_MOD     UINT_MAX
+#define XK_ANY_MOD    0
 
 #define SERRNO strerror(errno)
 #define MIN(a, b)  ((a) < (b) ? (a) : (b))
@@ -120,6 +126,7 @@ typedef struct {
 	Colormap cmap;
 	Window win;
 	Pixmap buf;
+	Atom xembed;
 	XIM xim;
 	XIC xic;
 	int scr;
@@ -217,6 +224,7 @@ static void visibility(XEvent *);
 static void unmap(XEvent *);
 static char* kmap(KeySym, unsigned int state);
 static void kpress(XEvent *);
+static void cmessage(XEvent *);
 static void resize(XEvent *);
 static void focus(XEvent *);
 static void brelease(XEvent *);
@@ -229,6 +237,7 @@ static void selinit(void);
 static inline int selected(int, int);
 static void selcopy(void);
 static void selpaste();
+static void selscroll(int, int);
 
 static int utf8decode(char *, long *);
 static int utf8encode(long *, char *);
@@ -237,6 +246,7 @@ static int isfullutf8(char *, int);
 
 static void (*handler[LASTEvent])(XEvent *) = {
 	[KeyPress] = kpress,
+	[ClientMessage] = cmessage,
 	[ConfigureNotify] = resize,
 	[VisibilityNotify] = visibility,
 	[UnmapNotify] = unmap,
@@ -797,6 +807,8 @@ tscrolldown(int orig, int n) {
 		term.line[i] = term.line[i-n];
 		term.line[i-n] = temp;
 	}
+
+	selscroll(orig, n);
 }
 
 void
@@ -812,6 +824,31 @@ tscrollup(int orig, int n) {
 		 term.line[i] = term.line[i+n];
 		 term.line[i+n] = temp;
 	}
+
+	selscroll(orig, -n);
+}
+
+void
+selscroll(int orig, int n) {
+	if(sel.bx == -1)
+		return;
+	
+	if(BETWEEN(sel.by, orig, term.bot) || BETWEEN(sel.ey, orig, term.bot)) {
+		if((sel.by += n) > term.bot || (sel.ey += n) < term.top) {
+			sel.bx = -1;
+			return;
+		}
+		if(sel.by < term.top) {
+			sel.by = term.top;
+			sel.bx = 0;
+		}
+		if(sel.ey > term.bot) {
+			sel.ey = term.bot;
+			sel.ex = term.col;
+		}
+		sel.b.y = sel.by, sel.b.x = sel.bx;
+		sel.e.y = sel.ey, sel.e.x = sel.ex;
+	}
 }
 
 void
@@ -1068,6 +1105,7 @@ csihandle(void) {
 		break;
 	/* XXX: (CSI n I) CHT -- Cursor Forward Tabulation <n> tab stops */
 	case 'J': /* ED -- Clear screen */
+		sel.bx = -1;
 		switch(escseq.arg[0]) {
 		case 0: /* below */
 			tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
@@ -1373,6 +1411,7 @@ tputc(char *c) {
 			}
 		}
 	} else {
+		if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey)) sel.bx = -1;
 		switch(ascii) {
 		case '\t':
 			tputtab();
@@ -1502,7 +1541,7 @@ xloadcols(void) {
 	XColor color;
 	unsigned long white = WhitePixel(xw.dpy, xw.scr);
 
-	for(i = 0; i < 16; i++) {
+	for(i = 0; i < LEN(colorname); i++) {
 		if(!XAllocNamedColor(xw.dpy, xw.cmap, colorname[i], &color, &color)) {
 			dc.col[i] = white;
 			fprintf(stderr, "Could not allocate color '%s'\n", colorname[i]);
@@ -1625,8 +1664,8 @@ xinit(void) {
 	xloadcols();
 
 	/* window - default size */
-	xw.bufh = 24 * xw.ch;
-	xw.bufw = 80 * xw.cw;
+	xw.bufh = term.row * xw.ch;
+	xw.bufw = term.col * xw.cw;
 	xw.h = xw.bufh + 2*BORDER;
 	xw.w = xw.bufw + 2*BORDER;
 
@@ -1635,7 +1674,8 @@ xinit(void) {
 	attrs.bit_gravity = NorthWestGravity;
 	attrs.event_mask = FocusChangeMask | KeyPressMask
 		| ExposureMask | VisibilityChangeMask | StructureNotifyMask
-		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
+		| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask
+		| EnterWindowMask | LeaveWindowMask;
 	attrs.colormap = xw.cmap;
 
 	parent = opt_embed ? strtol(opt_embed, NULL, 0) : XRootWindow(xw.dpy, xw.scr);
@@ -1663,6 +1703,8 @@ xinit(void) {
 		&(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff},
 		&(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
 
+	xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
+
 	XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st");
 	XMapWindow(xw.dpy, xw.win);
 	xhints();
@@ -1830,9 +1872,12 @@ focus(XEvent *ev) {
 char*
 kmap(KeySym k, unsigned int state) {
 	int i;
-	for(i = 0; i < LEN(key); i++)
-		if(key[i].k == k && (key[i].mask == 0 || key[i].mask & state))
+	state &= ~Mod2Mask;
+	for(i = 0; i < LEN(key); i++) {
+		unsigned int mask = key[i].mask;
+		if(key[i].k == k && ((state & mask) == mask || (mask == XK_NO_MOD && !state)))
 			return (char*)key[i].s;
+	}
 	return NULL;
 }
 
@@ -1886,6 +1931,21 @@ kpress(XEvent *ev) {
 		}
 }
 
+void
+cmessage(XEvent *e) {
+	/* See xembed specs
+	   http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html */
+	if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
+		if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
+			xw.state |= WIN_FOCUSED;
+			xseturgency(0);
+		} else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
+			xw.state &= ~WIN_FOCUSED;
+		}
+		draw();
+	}
+}
+
 void
 resize(XEvent *e) {
 	int col, row;