git.strcat.st

/strcat/sel.git/ - summarytreelogarchive

subject
init
commit
e30e4b6f79398df1c930b06f47a3db835e422aeb
date
2026-04-21T02:36:12Z
message
diff
 Makefile |  12 ++++
 sel.c    | 222 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 234 insertions(+)

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..9c0a062
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,12 @@
+CFLAGS   = -std=c89 -Wall -Wextra -Werror -pedantic
+CPPFLAGS = -I/usr/X11R6/include
+LDFLAGS  = -L/usr/X11R6/lib
+LDLIBS   = -lX11
+
+all: sel
+
+sel: sel.c
+	cc $(CPPFLAGS) $(CFLAGS) -o sel sel.c $(LDFLAGS) $(LDLIBS)
+
+clean:
+	rm -f sel
diff --git a/sel.c b/sel.c
new file mode 100644
index 0000000..ed151df
--- /dev/null
+++ b/sel.c
@@ -0,0 +1,222 @@
+#include <X11/Xlib.h>
+#include <X11/cursorfont.h>
+
+#include <stdio.h>
+
+static int
+min(int a, int b)
+{
+	return a < b ? a : b;
+}
+
+static int
+absd(int x)
+{
+	return x < 0 ? -x : x;
+}
+
+static int
+window_under_pointer(Display *dpy, Window root, Window *win)
+{
+	Window rootret, childret;
+	int rootx, rooty, winx, winy;
+	unsigned int mask;
+
+	if (!XQueryPointer(dpy, root, &rootret, &childret,
+	    &rootx, &rooty, &winx, &winy, &mask))
+	    return 0;
+	if (childret == None)
+	    return 0;
+	*win = childret;
+	return 1;
+}
+
+static int
+window_geometry_on_root(Display *dpy, Window root, Window win,
+    int *x, int *y, int *w, int *h)
+{
+	XWindowAttributes attr;
+	Window child;
+	int tx, ty;
+
+	if (!XGetWindowAttributes(dpy, win, &attr))
+	    return 0;
+	if (attr.map_state != IsViewable)
+	    return 0;
+	if (!XTranslateCoordinates(dpy, win, root, 0, 0, &tx, &ty, &child))
+	    return 0;
+	*x = tx;
+	*y = ty;
+	*w = attr.width;
+	*h = attr.height;
+	return 1;
+}
+
+int
+main(void)
+{
+	Display *dpy;
+	Window root;
+	Cursor cursor;
+	GC gc;
+	XGCValues gcv;
+	XEvent ev;
+	Window win;
+	int selecting;
+	int dragdrawn;
+	int hoverdrawn;
+	int sx, sy, ex, ey;
+	int dragx, dragy, dragw, dragh;
+	int hoverx, hovery, hoverw, hoverh;
+	int done;
+
+	if ((dpy = XOpenDisplay(NULL)) == NULL) {
+	    fprintf(stderr, "failed to open X display\n");
+	    return 1;
+	}
+	root = DefaultRootWindow(dpy);
+	cursor = XCreateFontCursor(dpy, XC_crosshair);
+
+	if (XGrabPointer(dpy, root, False,
+	    ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
+	    GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime) != GrabSuccess) {
+	    fprintf(stderr, "failed to grab pointer\n");
+	    XCloseDisplay(dpy);
+	    return 1;
+	}
+
+	gcv.function = GXinvert;
+	gcv.subwindow_mode = IncludeInferiors;
+	gcv.line_width = 1;
+	gcv.foreground = WhitePixel(dpy, DefaultScreen(dpy));
+	gc = XCreateGC(dpy, root,
+	    GCFunction | GCSubwindowMode | GCLineWidth | GCForeground, &gcv);
+
+	selecting = 0;
+	dragdrawn = 0;
+	hoverdrawn = 0;
+	sx = sy = ex = ey = 0;
+	dragx = dragy = dragw = dragh = 0;
+	hoverx = hovery = hoverw = hoverh = 0;
+	done = 0;
+
+	while (!done) {
+	    XNextEvent(dpy, &ev);
+
+	    if (ev.type == ButtonPress) {
+	        if (ev.xbutton.button != Button1) {
+	            done = 1;
+	            break;
+	        }
+
+	        if (hoverdrawn) {
+	            XDrawRectangle(dpy, root, gc,
+	                hoverx, hovery, (unsigned int)hoverw, (unsigned int)hoverh);
+	            XFlush(dpy);
+	            hoverdrawn = 0;
+	        }
+
+	        selecting = 1;
+	        sx = ev.xbutton.x_root;
+	        sy = ev.xbutton.y_root;
+	        ex = sx;
+	        ey = sy;
+	    } else if (ev.type == MotionNotify) {
+	        while (XCheckTypedEvent(dpy, MotionNotify, &ev))
+	            continue;
+
+	        if (selecting) {
+	            int x, y, w, h;
+
+	            if (dragdrawn)
+	                XDrawRectangle(dpy, root, gc,
+	                    dragx, dragy, (unsigned int)dragw, (unsigned int)dragh);
+
+	            ex = ev.xmotion.x_root;
+	            ey = ev.xmotion.y_root;
+	            x = min(sx, ex);
+	            y = min(sy, ey);
+	            w = absd(ex - sx);
+	            h = absd(ey - sy);
+	            XDrawRectangle(dpy, root, gc, x, y, (unsigned int)w, (unsigned int)h);
+	            XFlush(dpy);
+
+	            dragx = x;
+	            dragy = y;
+	            dragw = w;
+	            dragh = h;
+	            dragdrawn = 1;
+	        } else {
+	            int wx, wy, ww, wh;
+	            int have;
+
+	            have = 0;
+	            if (window_under_pointer(dpy, root, &win))
+	                have = window_geometry_on_root(dpy, root, win, &wx, &wy, &ww, &wh);
+
+	            if (have) {
+	                if (hoverdrawn &&
+	                    hoverx == wx && hovery == wy && hoverw == ww && hoverh == wh)
+	                    continue;
+
+	                if (hoverdrawn)
+	                    XDrawRectangle(dpy, root, gc,
+	                        hoverx, hovery,
+	                        (unsigned int)hoverw, (unsigned int)hoverh);
+	                XDrawRectangle(dpy, root, gc,
+	                    wx, wy, (unsigned int)ww, (unsigned int)wh);
+	                XFlush(dpy);
+
+	                hoverx = wx;
+	                hovery = wy;
+	                hoverw = ww;
+	                hoverh = wh;
+	                hoverdrawn = 1;
+	            } else if (hoverdrawn) {
+	                XDrawRectangle(dpy, root, gc,
+	                    hoverx, hovery, (unsigned int)hoverw, (unsigned int)hoverh);
+	                XFlush(dpy);
+	                hoverdrawn = 0;
+	            }
+	        }
+	    } else if (ev.type == ButtonRelease && selecting && ev.xbutton.button == Button1) {
+	        int outx, outy, outw, outh;
+
+	        if (dragdrawn) {
+	            XDrawRectangle(dpy, root, gc,
+	                dragx, dragy, (unsigned int)dragw, (unsigned int)dragh);
+	            XFlush(dpy);
+	            dragdrawn = 0;
+	        }
+
+	        ex = ev.xbutton.x_root;
+	        ey = ev.xbutton.y_root;
+	        outx = min(sx, ex);
+	        outy = min(sy, ey);
+	        outw = absd(ex - sx);
+	        outh = absd(ey - sy);
+
+	        if (outw == 0 || outh == 0) {
+	            if (window_under_pointer(dpy, root, &win))
+	                window_geometry_on_root(dpy, root, win,
+	                    &outx, &outy, &outw, &outh);
+	        }
+
+	        printf("%dx%d+%d+%d\n", outw, outh, outx, outy);
+	        fflush(stdout);
+	        done = 1;
+	    }
+	}
+
+	if (hoverdrawn) {
+	    XDrawRectangle(dpy, root, gc,
+	        hoverx, hovery, (unsigned int)hoverw, (unsigned int)hoverh);
+	    XFlush(dpy);
+	}
+
+	XFreeGC(dpy, gc);
+	XUngrabPointer(dpy, CurrentTime);
+	XFreeCursor(dpy, cursor);
+	XCloseDisplay(dpy);
+	return 0;
+}