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;
+}