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}