|
|
@ -0,0 +1,224 @@ |
|
|
|
/* xrectsel.c -- print the geometry of a rectangular screen region. |
|
|
|
|
|
|
|
Copyright (C) 2011-2014 lolilolicon <lolilolicon@gmail.com> |
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify |
|
|
|
it under the terms of the GNU General Public License as published by |
|
|
|
the Free Software Foundation, either version 3 of the License, or |
|
|
|
(at your option) any later version. |
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, |
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
|
GNU General Public License for more details. |
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License |
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
*/ |
|
|
|
|
|
|
|
#include <stdio.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <stdarg.h> |
|
|
|
#include <string.h> |
|
|
|
#include <X11/Xlib.h> |
|
|
|
#include <X11/cursorfont.h> |
|
|
|
|
|
|
|
#define die(args...) do {error(args); exit(EXIT_FAILURE); } while(0) |
|
|
|
|
|
|
|
typedef struct Region Region; |
|
|
|
struct Region { |
|
|
|
Window root; |
|
|
|
int x; /* offset from left of screen */ |
|
|
|
int y; /* offset from top of screen */ |
|
|
|
int X; /* offset from right of screen */ |
|
|
|
int Y; /* offset from bottom of screen */ |
|
|
|
unsigned int w; /* width */ |
|
|
|
unsigned int h; /* height */ |
|
|
|
unsigned int b; /* border_width */ |
|
|
|
unsigned int d; /* depth */ |
|
|
|
}; |
|
|
|
|
|
|
|
static void error(const char *errstr, ...); |
|
|
|
static int print_region_attr(const char *fmt, Region region); |
|
|
|
static int select_region(Display *dpy, Window root, Region *region); |
|
|
|
|
|
|
|
int main(int argc, const char *argv[]) |
|
|
|
{ |
|
|
|
Display *dpy; |
|
|
|
Window root; |
|
|
|
Region sr; /* selected region */ |
|
|
|
const char *fmt; /* format string */ |
|
|
|
|
|
|
|
dpy = XOpenDisplay(NULL); |
|
|
|
if (!dpy) { |
|
|
|
die("failed to open display %s\n", getenv("DISPLAY")); |
|
|
|
} |
|
|
|
|
|
|
|
root = DefaultRootWindow(dpy); |
|
|
|
|
|
|
|
fmt = argc > 1 ? argv[1] : "%wx%h+%x+%y\n"; |
|
|
|
|
|
|
|
/* interactively select a rectangular region */ |
|
|
|
if (select_region(dpy, root, &sr) != EXIT_SUCCESS) { |
|
|
|
XCloseDisplay(dpy); |
|
|
|
die("failed to select a rectangular region\n"); |
|
|
|
} |
|
|
|
|
|
|
|
print_region_attr(fmt, sr); |
|
|
|
|
|
|
|
XCloseDisplay(dpy); |
|
|
|
return EXIT_SUCCESS; |
|
|
|
} |
|
|
|
|
|
|
|
static void error(const char *errstr, ...) |
|
|
|
{ |
|
|
|
va_list ap; |
|
|
|
|
|
|
|
fprintf(stderr, "xrectsel: "); |
|
|
|
va_start(ap, errstr); |
|
|
|
vfprintf(stderr, errstr, ap); |
|
|
|
va_end(ap); |
|
|
|
} |
|
|
|
|
|
|
|
static int print_region_attr(const char *fmt, Region region) |
|
|
|
{ |
|
|
|
const char *s; |
|
|
|
|
|
|
|
for (s = fmt; *s; ++s) { |
|
|
|
if (*s == '%') { |
|
|
|
switch (*++s) { |
|
|
|
case '%': |
|
|
|
putchar('%'); |
|
|
|
break; |
|
|
|
case 'x': |
|
|
|
printf("%i", region.x); |
|
|
|
break; |
|
|
|
case 'y': |
|
|
|
printf("%i", region.y); |
|
|
|
break; |
|
|
|
case 'X': |
|
|
|
printf("%i", region.X); |
|
|
|
break; |
|
|
|
case 'Y': |
|
|
|
printf("%i", region.Y); |
|
|
|
break; |
|
|
|
case 'w': |
|
|
|
printf("%u", region.w); |
|
|
|
break; |
|
|
|
case 'h': |
|
|
|
printf("%u", region.h); |
|
|
|
break; |
|
|
|
case 'b': |
|
|
|
printf("%u", region.b); |
|
|
|
break; |
|
|
|
case 'd': |
|
|
|
printf("%u", region.d); |
|
|
|
break; |
|
|
|
} |
|
|
|
} else { |
|
|
|
putchar(*s); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int select_region(Display *dpy, Window root, Region *region) |
|
|
|
{ |
|
|
|
XEvent ev; |
|
|
|
|
|
|
|
GC sel_gc; |
|
|
|
XGCValues sel_gv; |
|
|
|
|
|
|
|
int done = 0, btn_pressed = 0; |
|
|
|
int x = 0, y = 0; |
|
|
|
unsigned int width = 0, height = 0; |
|
|
|
int start_x = 0, start_y = 0; |
|
|
|
|
|
|
|
Cursor cursor; |
|
|
|
cursor = XCreateFontCursor(dpy, XC_crosshair); |
|
|
|
|
|
|
|
/* Grab pointer for these events */ |
|
|
|
XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, |
|
|
|
GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime); |
|
|
|
|
|
|
|
sel_gv.function = GXinvert; |
|
|
|
sel_gv.subwindow_mode = IncludeInferiors; |
|
|
|
sel_gv.line_width = 1; |
|
|
|
sel_gc = XCreateGC(dpy, root, GCFunction | GCSubwindowMode | GCLineWidth, &sel_gv); |
|
|
|
|
|
|
|
for (;;) { |
|
|
|
XNextEvent(dpy, &ev); |
|
|
|
switch (ev.type) { |
|
|
|
case ButtonPress: |
|
|
|
btn_pressed = 1; |
|
|
|
x = start_x = ev.xbutton.x_root; |
|
|
|
y = start_y = ev.xbutton.y_root; |
|
|
|
width = height = 0; |
|
|
|
break; |
|
|
|
case MotionNotify: |
|
|
|
/* Draw only if button is pressed */ |
|
|
|
if (btn_pressed) { |
|
|
|
/* Re-draw last Rectangle to clear it */ |
|
|
|
XDrawRectangle(dpy, root, sel_gc, x, y, width, height); |
|
|
|
|
|
|
|
x = ev.xbutton.x_root; |
|
|
|
y = ev.xbutton.y_root; |
|
|
|
|
|
|
|
if (x > start_x) { |
|
|
|
width = x - start_x; |
|
|
|
x = start_x; |
|
|
|
} else { |
|
|
|
width = start_x - x; |
|
|
|
} |
|
|
|
if (y > start_y) { |
|
|
|
height = y - start_y; |
|
|
|
y = start_y; |
|
|
|
} else { |
|
|
|
height = start_y - y; |
|
|
|
} |
|
|
|
|
|
|
|
/* Draw Rectangle */ |
|
|
|
XDrawRectangle(dpy, root, sel_gc, x, y, width, height); |
|
|
|
XFlush(dpy); |
|
|
|
} |
|
|
|
break; |
|
|
|
case ButtonRelease: |
|
|
|
done = 1; |
|
|
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
if (done) |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
/* Re-draw last Rectangle to clear it */ |
|
|
|
XDrawRectangle(dpy, root, sel_gc, x, y, width, height); |
|
|
|
XFlush(dpy); |
|
|
|
|
|
|
|
XUngrabPointer(dpy, CurrentTime); |
|
|
|
XFreeCursor(dpy, cursor); |
|
|
|
XFreeGC(dpy, sel_gc); |
|
|
|
XSync(dpy, 1); |
|
|
|
|
|
|
|
Region rr; /* root region */ |
|
|
|
Region sr; /* selected region */ |
|
|
|
|
|
|
|
if (False == XGetGeometry(dpy, root, &rr.root, &rr.x, &rr.y, &rr.w, &rr.h, &rr.b, &rr.d)) { |
|
|
|
error("failed to get root window geometry\n"); |
|
|
|
return EXIT_FAILURE; |
|
|
|
} |
|
|
|
sr.x = x; |
|
|
|
sr.y = y; |
|
|
|
sr.w = width; |
|
|
|
sr.h = height; |
|
|
|
/* calculate right and bottom offset */ |
|
|
|
sr.X = rr.w - sr.x - sr.w; |
|
|
|
sr.Y = rr.h - sr.y - sr.h; |
|
|
|
/* those doesn't really make sense but should be set */ |
|
|
|
sr.b = rr.b; |
|
|
|
sr.d = rr.d; |
|
|
|
*region = sr; |
|
|
|
return EXIT_SUCCESS; |
|
|
|
} |