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.

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