print the geometry of a rectangular screen region
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

224 lines
5.5 KiB

/* 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;
}