xsnip

X11 screenshotter
git clone https://git.sinitax.com/sinitax/xsnip
Log | Files | Refs | LICENSE | sfeed.txt

xsnip.c (3539B)


      1#include <Imlib2.h>
      2#include <X11/Xlib.h>
      3#include <X11/XKBlib.h>
      4#include <X11/keysym.h>
      5#include <X11/cursorfont.h>
      6
      7#include <unistd.h>
      8#include <err.h>
      9#include <stdio.h>
     10#include <stdlib.h>
     11#include <stdarg.h>
     12#include <string.h>
     13
     14#define MIN(a, b) ((a) < (b) ? (a) : (b))
     15#define MAX(a, b) ((a) >= (b) ? (a) : (b))
     16
     17static const char usage[] = "xsnip [-h] [-d DELAY] OUTFILE";
     18
     19static const char *filename;
     20
     21static XWindowAttributes scr;
     22static Display *display;
     23static Window root, win;
     24static int rx, ry, rw, rh;
     25static GC gc;
     26
     27void
     28update(int x1, int y1, int x2, int y2)
     29{
     30	rx = MIN(x1, x2);
     31	ry = MIN(y1, y2);
     32	rw = MAX(1, MAX(x1, x2) - MIN(x1, x2));
     33	rh = MAX(1, MAX(y1, y2) - MIN(y1, y2));
     34}
     35
     36void
     37init(void)
     38{
     39	XSetWindowAttributes swa;
     40	XGCValues gcvals;
     41	Screen *screen;
     42
     43	display = XOpenDisplay(NULL);
     44	screen = XDefaultScreenOfDisplay(display);
     45
     46	root = DefaultRootWindow(display);
     47	XGetWindowAttributes(display, root, &scr);
     48
     49	swa.override_redirect = 1;
     50	win = XCreateWindow(display, root, scr.x, scr.y, scr.width, scr.height,
     51		0, CopyFromParent, InputOutput, CopyFromParent,
     52		CWOverrideRedirect, &swa);
     53	XMapWindow(display, win);
     54
     55	gcvals = (XGCValues) { 0 };
     56	gcvals.foreground = XWhitePixelOfScreen(screen);
     57	gcvals.function = GXxor;
     58	gc = XCreateGC(display, win, GCFunction | GCForeground, &gcvals);
     59}
     60
     61void
     62deinit(void)
     63{
     64	XDestroyWindow(display, win);
     65	XCloseDisplay(display);
     66}
     67
     68void
     69saveimg(void)
     70{
     71	Imlib_Image img;
     72
     73	imlib_context_set_display(display);
     74	imlib_context_set_visual(DefaultVisual(display, 0));
     75	imlib_context_set_drawable(win);
     76
     77	img = imlib_create_image_from_drawable(0, rx, ry, rw, rh, 1);
     78
     79	imlib_context_set_image(img);
     80	imlib_save_image(filename);
     81	imlib_free_image();
     82}
     83
     84void
     85capture(void)
     86{
     87	int draw, dirty, done;
     88	int px, py, x, y, keysym;
     89	Cursor cursor;
     90	XEvent ev;
     91
     92	cursor = XCreateFontCursor(display, XC_left_ptr);
     93
     94	XGrabPointer(display, root, False,
     95		ButtonMotionMask | ButtonPressMask | ButtonReleaseMask,
     96		GrabModeAsync, GrabModeAsync, root, cursor, CurrentTime);
     97
     98	XGrabKeyboard(display, root, False, GrabModeAsync,
     99		GrabModeAsync, CurrentTime);
    100
    101	done = dirty = 0;
    102	while (!done) {
    103		if (!XPending(display)) continue;
    104		XNextEvent(display, &ev);
    105		switch (ev.type) {
    106		case KeyPress:
    107			keysym = XkbKeycodeToKeysym(display, ev.xkey.keycode, 0,
    108				ev.xkey.state & ShiftMask ? 1 : 0);
    109			if (keysym == XK_Escape) {
    110				deinit();
    111				exit(1);
    112			}
    113			break;
    114		case MotionNotify:
    115			if (draw && dirty) {
    116				XDrawRectangle(display, win, gc,
    117					rx, ry, rw, rh);
    118			}
    119
    120			x = ev.xmotion.x;
    121			y = ev.xmotion.y;
    122			update(px, py, x, y);
    123
    124			if (draw) {
    125				XDrawRectangle(display, win, gc,
    126					rx, ry, rw, rh);
    127				dirty = 1;
    128				XFlush(display);
    129			}
    130			break;
    131		case ButtonPress:
    132			px = ev.xbutton.x;
    133			py = ev.xbutton.y;
    134			draw = 1;
    135			break;
    136		case ButtonRelease:
    137			done = 1;
    138			break;
    139		}
    140	}
    141
    142	XDrawRectangle(display, win, gc,
    143		rx, ry, rw, rh);
    144}
    145
    146int
    147main(int argc, char **argv)
    148{
    149	char **arg, *end;
    150	int delay;
    151
    152	delay = 0;
    153	filename = NULL;
    154	for (arg = &argv[1]; *arg; arg++) {
    155		if (!strcmp(*arg, "-d")) {
    156			delay = strtol(*(++arg), &end, 10);
    157			if (end && *end || delay <= 0)
    158				errx(1, "Invalid delay");
    159		} else if (!strcmp(*arg, "-h")) {
    160			printf("Usage: %s\n", usage);
    161			return 0;
    162		} else if (!filename) {
    163			filename = *arg;
    164		} else {
    165			fprintf(stderr, "Usage: %s\n", usage);
    166			return 1;
    167		}
    168	}
    169
    170	if (!filename) {
    171		fprintf(stderr, "USAGE: %s\n", usage);
    172		return 1;
    173	}
    174
    175	if (delay) sleep(delay);
    176
    177	init();
    178
    179	capture();
    180
    181	saveimg();
    182
    183	deinit();
    184}