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 | ||
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 | ||
0ddb7051 | 73 | i_img * |
87cd516f | 74 | imss_win32(unsigned hwnd_u, int include_decor, int left, int top, |
4e6ce56a | 75 | int right, int bottom, int display) { |
0ddb7051 | 76 | HWND hwnd = (HWND)hwnd_u; |
ece126f9 | 77 | HDC cdc = 0, wdc; |
4e6ce56a TC |
78 | int orig_x = 0; |
79 | int orig_y = 0; | |
87cd516f | 80 | int window_width, window_height; |
0ddb7051 | 81 | i_img *result = NULL; |
87cd516f | 82 | int width, height; |
ece126f9 | 83 | int channels = 3; |
0ddb7051 TC |
84 | |
85 | i_clear_error(); | |
86 | ||
4e6ce56a TC |
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 | } | |
0ddb7051 | 101 | |
4e6ce56a TC |
102 | window_width = rect.right - rect.left; |
103 | window_height = rect.bottom - rect.top; | |
0ddb7051 TC |
104 | } |
105 | else { | |
4e6ce56a | 106 | if (display == -1) { |
4e6ce56a TC |
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); | |
ece126f9 | 112 | channels = 4; |
4e6ce56a TC |
113 | } |
114 | else { | |
115 | DISPLAY_DEVICE dd; | |
116 | dd.cb = sizeof(dd); | |
0ddb7051 | 117 | |
4e6ce56a | 118 | if (EnumDisplayDevices(NULL, display, &dd, 0)) { |
ece126f9 | 119 | printf("Flags %lx\n", (unsigned long)dd.StateFlags); |
f7119376 TC |
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 | } | |
4e6ce56a TC |
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 | } | |
87cd516f TC |
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"); | |
f7119376 TC |
163 | if (cdc) |
164 | DeleteDC(cdc); | |
165 | else | |
166 | ReleaseDC(hwnd, wdc); | |
87cd516f TC |
167 | return NULL; |
168 | } | |
169 | width = right - left; | |
170 | height = bottom - top; | |
ece126f9 TC |
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; | |
0ddb7051 | 191 | } |
0ddb7051 | 192 | } |
0ddb7051 | 193 | /* clean up */ |
4e6ce56a TC |
194 | if (cdc) { |
195 | DeleteDC(cdc); | |
196 | } | |
197 | else { | |
198 | ReleaseDC(hwnd, wdc); | |
199 | } | |
0ddb7051 TC |
200 | |
201 | return result; | |
202 | } |