Commit | Line | Data |
---|---|---|
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 | 11 | struct monitor_ctx { |
ece126f9 TC |
12 | i_img *out; |
13 | i_img_dim orig_x, orig_y; | |
6d37c2c9 | 14 | int good; |
ece126f9 TC |
15 | }; |
16 | ||
17 | static int | |
18 | display_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 |
75 | static BOOL CALLBACK |
76 | monitor_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 | 88 | i_img * |
87cd516f | 89 | imss_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 | } |