8e9b6bc4c32ca380252c0e02401d04365ee56388
[imager-screenshot.git] / scx11.c
1 #include "imext.h"
2 #include <X11/Xlib.h>
3
4 static
5 int
6 my_handler(Display *display, XErrorEvent *error) {
7   char buffer[500];
8
9   XGetErrorText(display, error->error_code, buffer, sizeof(buffer));
10   i_push_error(error->error_code, buffer);
11 }
12
13 i_img *
14 imss_x11(unsigned long display_ul, unsigned long window_id) {
15   Display *display = (Display *)display_ul;
16   int own_display = 0; /* non-zero if we connect */
17   GC gc;
18   XImage *image;
19   XWindowAttributes attr;
20   i_img *result;
21   i_color *line, *cp;
22   int x, y;
23   XColor *colors;
24   XErrorHandler old_handler;
25
26   i_clear_error();
27
28   /* we don't want the default noisy error handling */
29   old_handler = XSetErrorHandler(my_handler);
30
31   if (!display) {
32     display = XOpenDisplay(NULL);
33     ++own_display;
34     if (!display) {
35       XSetErrorHandler(old_handler);
36       i_push_error(0, "No display supplied and cannot connect");
37       return NULL;
38     }
39   }
40
41   if (!window_id) {
42     int screen = DefaultScreen(display);
43     window_id = RootWindow(display, 0);
44   }
45
46   if (!XGetWindowAttributes(display, window_id, &attr)) {
47     XSetErrorHandler(old_handler);
48     if (own_display)
49       XCloseDisplay(display);
50     i_push_error(0, "Cannot XGetWindowAttributes");
51     return NULL;
52   }
53
54   image = XGetImage(display, window_id, 0, 0, attr.width, attr.height,
55                     -1, ZPixmap);
56   if (!image) {
57     XSetErrorHandler(old_handler);
58     if (own_display)
59       XCloseDisplay(display);
60     i_push_error(0, "Cannot XGetImage");
61     return NULL;
62   }
63
64   result = i_img_8_new(attr.width, attr.height, 3);
65   line = mymalloc(sizeof(i_color) * attr.width);
66   colors = mymalloc(sizeof(XColor) * attr.width);
67   for (y = 0; y < attr.height; ++y) {
68     cp = line;
69     /* XQueryColors seems to be a round-trip, so do one big request
70        instead of one per pixel */
71     for (x = 0; x < attr.width; ++x) {
72       colors[x].pixel = XGetPixel(image, x, y);
73     }
74     XQueryColors(display, attr.colormap, colors, attr.width);
75     for (x = 0; x < attr.width; ++x) {
76       cp->rgb.r = colors[x].red >> 8;
77       cp->rgb.g = colors[x].green >> 8;
78       cp->rgb.b = colors[x].blue >> 8;
79       ++cp;
80     }
81     i_plin(result, 0, attr.width, y, line);
82   }
83
84   XSetErrorHandler(old_handler);
85   if (own_display)
86     XCloseDisplay(display);
87
88   return result;
89 }
90
91 unsigned long
92 imss_x11_open(char const *display_name) {
93   XErrorHandler old_handler;
94   Display *display;
95
96   i_clear_error();
97   XSetErrorHandler(my_handler);
98   display = XOpenDisplay(display_name);
99   if (!display)
100     i_push_errorf(0, "Cannot connect to X server %s", XDisplayName(display_name));
101   
102   XSetErrorHandler(old_handler);
103
104   return (unsigned long)display;
105 }
106
107 void
108 imss_x11_close(unsigned long display) {
109   XCloseDisplay((Display *)display);
110 }