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 
     17 static const char usage[] = "xsnip [-h] [-d DELAY] OUTFILE";
     18 
     19 static const char *filename;
     20 
     21 static XWindowAttributes scr;
     22 static Display *display;
     23 static Window root, win;
     24 static int rx, ry, rw, rh;
     25 static GC gc;
     26 
     27 void
     28 update(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 
     36 void
     37 init(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 
     61 void
     62 deinit(void)
     63 {
     64 	XDestroyWindow(display, win);
     65 	XCloseDisplay(display);
     66 }
     67 
     68 void
     69 saveimg(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 
     84 void
     85 capture(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 
    146 int
    147 main(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 }