itermediate working result
[imager-screenshot.git] / scwin32.c
1 #include "imext.h"
2 #include <windows.h>
3 #include <string.h>
4 #include "imss.h"
5
6 /* the SDK headers supplied with cygwin, and with some older strawberry perls */
7 #ifndef DISPLAY_DEVICE_ACTIVE
8 #define DISPLAY_DEVICE_ACTIVE 1
9 #endif
10
11 struct moniter_ctx {
12   i_img *out;
13   i_img_dim orig_x, orig_y;
14 };
15
16 static int
17 display_to_img(HDC dc, i_img *im, const RECT *src, int dest_x, int dest_y) {
18   HBITMAP work_bmp;
19   HDC bmdc;
20   HBITMAP old_dc_bmp;
21   i_img_dim width = src->right - src->left;
22   i_img_dim height = src->bottom - src->top;
23   int result = 0;
24   BITMAPINFO bmi;
25   unsigned char *di_bits;
26
27   work_bmp = CreateCompatibleBitmap(dc, width, height);
28   bmdc = CreateCompatibleDC(dc);
29   old_dc_bmp = SelectObject(bmdc, work_bmp);
30   BitBlt(bmdc, 0, 0, width, height, dc, src->left, src->top, SRCCOPY);
31
32   /* make a dib */
33   memset(&bmi, 0, sizeof(bmi));
34   bmi.bmiHeader.biSize = sizeof(bmi);
35   bmi.bmiHeader.biWidth = width;
36   bmi.bmiHeader.biHeight = -height;
37   bmi.bmiHeader.biPlanes = 1;
38   bmi.bmiHeader.biBitCount = 32;
39   bmi.bmiHeader.biCompression = BI_RGB;
40
41   di_bits = mymalloc(4 * width * height);
42   if (GetDIBits(bmdc, work_bmp, 0, height, di_bits, &bmi, DIB_RGB_COLORS)) {
43     i_color *line = mymalloc(sizeof(i_color) * width);
44     i_color *cp;
45     int x, y;
46     unsigned char *ch_pp = di_bits;
47     for (y = 0; y < height; ++y) {
48       cp = line;
49       for (x = 0; x < width; ++x) {
50         cp->rgb.b = *ch_pp++;
51         cp->rgb.g = *ch_pp++;
52         cp->rgb.r = *ch_pp++;
53         ch_pp++;
54         cp++;
55       }
56       i_plin(im, dest_x, width, dest_y + y, line);
57     }
58     myfree(line);
59     result = 1;
60   }
61   else {
62     i_push_errorf(0, "GetDIBits() failure %d", (long)GetLastError());
63   }
64
65   myfree(di_bits);
66   SelectObject(bmdc, old_dc_bmp);
67   DeleteDC(bmdc);
68   DeleteObject(work_bmp);
69
70   return result;
71 }
72
73 i_img *
74 imss_win32(unsigned hwnd_u, int include_decor, int left, int top, 
75            int right, int bottom, int display) {
76   HWND hwnd = (HWND)hwnd_u;
77   HDC cdc = 0, wdc;
78   int orig_x = 0;
79   int orig_y = 0;
80   int window_width, window_height;
81   i_img *result = NULL;
82   int width, height;
83   int channels = 3;
84
85   i_clear_error();
86
87   if (hwnd) {
88     RECT rect;
89     if (include_decor) {
90       wdc = GetWindowDC(hwnd);
91       GetWindowRect(hwnd, &rect);
92     }
93     else {
94       wdc = GetDC(hwnd);
95       GetClientRect(hwnd, &rect);
96     }
97     if (!wdc) {
98       i_push_error(0, "Cannot get window DC - invalid hwnd?");
99       return NULL;
100     }
101
102     window_width = rect.right - rect.left;
103     window_height = rect.bottom - rect.top;
104   }
105   else {
106     if (display == -1) {
107       cdc = CreateDC("DISPLAY", NULL, NULL, NULL);
108       orig_x = GetSystemMetrics(SM_XVIRTUALSCREEN);
109       orig_y = GetSystemMetrics(SM_YVIRTUALSCREEN);
110       window_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
111       window_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
112       channels = 4;
113     }
114     else {
115       DISPLAY_DEVICE dd;
116       dd.cb = sizeof(dd);
117
118       if (EnumDisplayDevices(NULL, display, &dd, 0)) {
119         printf("Flags %lx\n", (unsigned long)dd.StateFlags);
120         if (dd.StateFlags & DISPLAY_DEVICE_ACTIVE) {
121           cdc = CreateDC(dd.DeviceName, dd.DeviceName, NULL, NULL);
122         }
123         else {
124           i_push_errorf(0, "Display device %d not active", display);
125           return NULL;
126         }
127       }
128       else {
129         i_push_errorf(0, "Cannot enumerate device %d: %ld", display, (long)GetLastError());
130         return NULL;
131       }
132
133       window_width = GetDeviceCaps(cdc, HORZRES);
134       window_height = GetDeviceCaps(cdc, VERTRES);
135     }
136
137     wdc = cdc;
138   }
139
140   /* adjust negative/zero values to window size */
141   if (left < 0)
142     left += window_width;
143   if (top < 0)
144     top += window_height;
145   if (right <= 0)
146     right += window_width;
147   if (bottom <= 0)
148     bottom += window_height;
149   
150   /* clamp */
151   if (left < 0)
152     left = 0;
153   if (right > window_width)
154     right = window_width;
155   if (top < 0)
156     top = 0;
157   if (bottom > window_height)
158     bottom = window_height;
159
160   /* validate */
161   if (right <= left || bottom <= top) {
162     i_push_error(0, "image would be empty");
163     if (cdc)
164       DeleteDC(cdc);
165     else
166       ReleaseDC(hwnd, wdc);
167     return NULL;
168   }
169   width = right - left;
170   height = bottom - top;
171   
172   result = i_img_8_new(width, height, channels);
173   
174   if (result) {
175     RECT r;
176     r.left = orig_x + left;
177     r.top = orig_y + top;
178     r.right = r.left + width;
179     r.bottom = r.top + height;
180     
181     if (display_to_img(wdc, result, &r, 0, 0)) {
182       i_tags_setn(&result->tags, "ss_window_width", window_width);
183       i_tags_setn(&result->tags, "ss_window_height", window_height);
184       i_tags_set(&result->tags, "ss_type", "Win32", 5);
185       i_tags_setn(&result->tags, "ss_left", left);
186       i_tags_setn(&result->tags, "ss_top", top);
187     }
188     else {
189       i_img_destroy(result);
190       result = NULL;
191     }
192   }
193   /* clean up */
194   if (cdc) {
195     DeleteDC(cdc);
196   }
197   else {
198     ReleaseDC(hwnd, wdc);
199   }
200
201   return result;
202 }