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