#include #include #include 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; }