]> git.imager.perl.org - imager-screenshot.git/blame - scx11.c
include NA in the die output as suggested by
[imager-screenshot.git] / scx11.c
CommitLineData
b2239557
TC
1#include "imext.h"
2#include <X11/Xlib.h>
87cd516f
TC
3#include <X11/Xutil.h>
4#include "imss.h"
b2239557
TC
5
6static
7int
8my_handler(Display *display, XErrorEvent *error) {
9 char buffer[500];
10
11 XGetErrorText(display, error->error_code, buffer, sizeof(buffer));
12 i_push_error(error->error_code, buffer);
87cd516f
TC
13
14 return 0;
b2239557
TC
15}
16
17i_img *
87cd516f
TC
18imss_x11(unsigned long display_ul, int window_id,
19 int left, int top, int right, int bottom) {
b2239557
TC
20 Display *display = (Display *)display_ul;
21 int own_display = 0; /* non-zero if we connect */
b2239557
TC
22 XImage *image;
23 XWindowAttributes attr;
24 i_img *result;
25 i_color *line, *cp;
26 int x, y;
27 XColor *colors;
28 XErrorHandler old_handler;
87cd516f 29 int width, height;
b2239557
TC
30
31 i_clear_error();
32
33 /* we don't want the default noisy error handling */
34 old_handler = XSetErrorHandler(my_handler);
35
36 if (!display) {
37 display = XOpenDisplay(NULL);
38 ++own_display;
39 if (!display) {
40 XSetErrorHandler(old_handler);
41 i_push_error(0, "No display supplied and cannot connect");
42 return NULL;
43 }
44 }
45
46 if (!window_id) {
47 int screen = DefaultScreen(display);
62b84c46 48 window_id = RootWindow(display, screen);
b2239557
TC
49 }
50
51 if (!XGetWindowAttributes(display, window_id, &attr)) {
52 XSetErrorHandler(old_handler);
53 if (own_display)
54 XCloseDisplay(display);
55 i_push_error(0, "Cannot XGetWindowAttributes");
56 return NULL;
57 }
58
87cd516f
TC
59 /* adjust negative/zero values to window size */
60 if (left < 0)
61 left += attr.width;
62 if (top < 0)
63 top += attr.height;
64 if (right <= 0)
65 right += attr.width;
66 if (bottom <= 0)
67 bottom += attr.height;
68
69 /* clamp */
70 if (left < 0)
71 left = 0;
72 if (right > attr.width)
73 right = attr.width;
74 if (top < 0)
75 top = 0;
76 if (bottom > attr.height)
77 bottom = attr.height;
78
79 /* validate */
80 if (right <= left || bottom <= top) {
81 XSetErrorHandler(old_handler);
82 if (own_display)
83 XCloseDisplay(display);
84 i_push_error(0, "image would be empty");
85 return NULL;
86 }
87 width = right - left;
88 height = bottom - top;
89 image = XGetImage(display, window_id, left, top, width, height,
b2239557
TC
90 -1, ZPixmap);
91 if (!image) {
92 XSetErrorHandler(old_handler);
93 if (own_display)
94 XCloseDisplay(display);
95 i_push_error(0, "Cannot XGetImage");
96 return NULL;
97 }
98
87cd516f
TC
99 result = i_img_8_new(width, height, 3);
100 line = mymalloc(sizeof(i_color) * width);
101 colors = mymalloc(sizeof(XColor) * width);
102 for (y = 0; y < height; ++y) {
b2239557
TC
103 cp = line;
104 /* XQueryColors seems to be a round-trip, so do one big request
105 instead of one per pixel */
87cd516f 106 for (x = 0; x < width; ++x) {
b2239557
TC
107 colors[x].pixel = XGetPixel(image, x, y);
108 }
87cd516f
TC
109 XQueryColors(display, attr.colormap, colors, width);
110 for (x = 0; x < width; ++x) {
b2239557
TC
111 cp->rgb.r = colors[x].red >> 8;
112 cp->rgb.g = colors[x].green >> 8;
113 cp->rgb.b = colors[x].blue >> 8;
114 ++cp;
115 }
87cd516f 116 i_plin(result, 0, width, y, line);
b2239557 117 }
bc7a6f7b
TC
118 myfree(line);
119 myfree(colors);
120 XDestroyImage(image);
b2239557
TC
121
122 XSetErrorHandler(old_handler);
123 if (own_display)
124 XCloseDisplay(display);
125
62b84c46
TC
126 i_tags_setn(&result->tags, "ss_window_width", attr.width);
127 i_tags_setn(&result->tags, "ss_window_height", attr.height);
128 i_tags_set(&result->tags, "ss_type", "X11", 3);
129 i_tags_setn(&result->tags, "ss_left", left);
130 i_tags_setn(&result->tags, "ss_top", top);
131
b2239557
TC
132 return result;
133}
134
135unsigned long
136imss_x11_open(char const *display_name) {
137 XErrorHandler old_handler;
138 Display *display;
139
140 i_clear_error();
bc7a6f7b 141 old_handler = XSetErrorHandler(my_handler);
b2239557
TC
142 display = XOpenDisplay(display_name);
143 if (!display)
144 i_push_errorf(0, "Cannot connect to X server %s", XDisplayName(display_name));
145
146 XSetErrorHandler(old_handler);
147
148 return (unsigned long)display;
149}
150
151void
152imss_x11_close(unsigned long display) {
153 XCloseDisplay((Display *)display);
154}