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

  1. /* xrectsel.c -- print the geometry of a rectangular screen region.
  2. Copyright (C) 2011-2014 lolilolicon <lolilolicon@gmail.com>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <stdarg.h>
  17. #include <string.h>
  18. #include <X11/Xlib.h>
  19. #include <X11/cursorfont.h>
  20. #define die(args...) do {error(args); exit(EXIT_FAILURE); } while(0)
  21. typedef struct Region Region;
  22. struct Region {
  23. Window root;
  24. int x; /* offset from left of screen */
  25. int y; /* offset from top of screen */
  26. int X; /* offset from right of screen */
  27. int Y; /* offset from bottom of screen */
  28. unsigned int w; /* width */
  29. unsigned int h; /* height */
  30. unsigned int b; /* border_width */
  31. unsigned int d; /* depth */
  32. };
  33. static void error(const char *errstr, ...);
  34. static int print_region_attr(const char *fmt, Region region);
  35. static int select_region(Display *dpy, Window root, Region *region);
  36. int main(int argc, const char *argv[])
  37. {
  38. Display *dpy;
  39. Window root;
  40. Region sr; /* selected region */
  41. const char *fmt; /* format string */
  42. dpy = XOpenDisplay(NULL);
  43. if (!dpy) {
  44. die("failed to open display %s\n", getenv("DISPLAY"));
  45. }
  46. root = DefaultRootWindow(dpy);
  47. fmt = argc > 1 ? argv[1] : "%wx%h+%x+%y\n";
  48. /* interactively select a rectangular region */
  49. if (select_region(dpy, root, &sr) != EXIT_SUCCESS) {
  50. XCloseDisplay(dpy);
  51. die("failed to select a rectangular region\n");
  52. }
  53. print_region_attr(fmt, sr);
  54. XCloseDisplay(dpy);
  55. return EXIT_SUCCESS;
  56. }
  57. static void error(const char *errstr, ...)
  58. {
  59. va_list ap;
  60. fprintf(stderr, "xrectsel: ");
  61. va_start(ap, errstr);
  62. vfprintf(stderr, errstr, ap);
  63. va_end(ap);
  64. }
  65. static int print_region_attr(const char *fmt, Region region)
  66. {
  67. const char *s;
  68. for (s = fmt; *s; ++s) {
  69. if (*s == '%') {
  70. switch (*++s) {
  71. case '%':
  72. putchar('%');
  73. break;
  74. case 'x':
  75. printf("%i", region.x);
  76. break;
  77. case 'y':
  78. printf("%i", region.y);
  79. break;
  80. case 'X':
  81. printf("%i", region.X);
  82. break;
  83. case 'Y':
  84. printf("%i", region.Y);
  85. break;
  86. case 'w':
  87. printf("%u", region.w);
  88. break;
  89. case 'h':
  90. printf("%u", region.h);
  91. break;
  92. case 'b':
  93. printf("%u", region.b);
  94. break;
  95. case 'd':
  96. printf("%u", region.d);
  97. break;
  98. }
  99. } else {
  100. putchar(*s);
  101. }
  102. }
  103. return 0;
  104. }
  105. static int select_region(Display *dpy, Window root, Region *region)
  106. {
  107. XEvent ev;
  108. GC sel_gc;
  109. XGCValues sel_gv;
  110. int done = 0, btn_pressed = 0;
  111. int x = 0, y = 0;
  112. unsigned int width = 0, height = 0;
  113. int start_x = 0, start_y = 0;
  114. Cursor cursor;
  115. cursor = XCreateFontCursor(dpy, XC_crosshair);
  116. /* Grab pointer for these events */
  117. XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
  118. GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
  119. sel_gv.function = GXinvert;
  120. sel_gv.subwindow_mode = IncludeInferiors;
  121. sel_gv.line_width = 1;
  122. sel_gc = XCreateGC(dpy, root, GCFunction | GCSubwindowMode | GCLineWidth, &sel_gv);
  123. for (;;) {
  124. XNextEvent(dpy, &ev);
  125. switch (ev.type) {
  126. case ButtonPress:
  127. btn_pressed = 1;
  128. x = start_x = ev.xbutton.x_root;
  129. y = start_y = ev.xbutton.y_root;
  130. width = height = 0;
  131. break;
  132. case MotionNotify:
  133. /* Draw only if button is pressed */
  134. if (btn_pressed) {
  135. /* Re-draw last Rectangle to clear it */
  136. XDrawRectangle(dpy, root, sel_gc, x, y, width, height);
  137. x = ev.xbutton.x_root;
  138. y = ev.xbutton.y_root;
  139. if (x > start_x) {
  140. width = x - start_x;
  141. x = start_x;
  142. } else {
  143. width = start_x - x;
  144. }
  145. if (y > start_y) {
  146. height = y - start_y;
  147. y = start_y;
  148. } else {
  149. height = start_y - y;
  150. }
  151. /* Draw Rectangle */
  152. XDrawRectangle(dpy, root, sel_gc, x, y, width, height);
  153. XFlush(dpy);
  154. }
  155. break;
  156. case ButtonRelease:
  157. done = 1;
  158. break;
  159. default:
  160. break;
  161. }
  162. if (done)
  163. break;
  164. }
  165. /* Re-draw last Rectangle to clear it */
  166. XDrawRectangle(dpy, root, sel_gc, x, y, width, height);
  167. XFlush(dpy);
  168. XUngrabPointer(dpy, CurrentTime);
  169. XFreeCursor(dpy, cursor);
  170. XFreeGC(dpy, sel_gc);
  171. XSync(dpy, 1);
  172. Region rr; /* root region */
  173. Region sr; /* selected region */
  174. if (False == XGetGeometry(dpy, root, &rr.root, &rr.x, &rr.y, &rr.w, &rr.h, &rr.b, &rr.d)) {
  175. error("failed to get root window geometry\n");
  176. return EXIT_FAILURE;
  177. }
  178. sr.x = x;
  179. sr.y = y;
  180. sr.w = width;
  181. sr.h = height;
  182. /* calculate right and bottom offset */
  183. sr.X = rr.w - sr.x - sr.w;
  184. sr.Y = rr.h - sr.y - sr.h;
  185. /* those doesn't really make sense but should be set */
  186. sr.b = rr.b;
  187. sr.d = rr.d;
  188. *region = sr;
  189. return EXIT_SUCCESS;
  190. }