first pass at multi-monitor capture
[imager-screenshot.git] / scwin32.c
1 #include "imext.h"
2 #include <windows.h>
3 #include <string.h>
4 #include "imss.h"
5
6 i_img *
7 imss_win32(unsigned hwnd_u, int include_decor, int left, int top, 
8            int right, int bottom, int display) {
9   HWND hwnd = (HWND)hwnd_u;
10   HDC cdc = 0, wdc, bmdc;
11   HBITMAP work_bmp, old_dc_bmp;
12   int orig_x = 0;
13   int orig_y = 0;
14   int window_width, window_height;
15   BITMAPINFO bmi;
16   unsigned char *di_bits;
17   i_img *result = NULL;
18   int width, height;
19
20   i_clear_error();
21
22   if (hwnd) {
23     RECT rect;
24     if (include_decor) {
25       wdc = GetWindowDC(hwnd);
26       GetWindowRect(hwnd, &rect);
27     }
28     else {
29       wdc = GetDC(hwnd);
30       GetClientRect(hwnd, &rect);
31     }
32     if (!wdc) {
33       i_push_error(0, "Cannot get window DC - invalid hwnd?");
34       return NULL;
35     }
36
37     window_width = rect.right - rect.left;
38     window_height = rect.bottom - rect.top;
39   }
40   else {
41     if (display == -1) {
42       fprintf(stderr, "all desktops\n");
43       cdc = CreateDC("DISPLAY", NULL, NULL, NULL);
44       orig_x = GetSystemMetrics(SM_XVIRTUALSCREEN);
45       orig_y = GetSystemMetrics(SM_YVIRTUALSCREEN);
46       window_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
47       window_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
48     }
49     else {
50       DISPLAY_DEVICE dd;
51       dd.cb = sizeof(dd);
52
53       if (EnumDisplayDevices(NULL, display, &dd, 0)) {
54         fprintf(stderr, "found %d ->  %s\n", display, dd.DeviceName);
55         cdc = CreateDC(dd.DeviceName, dd.DeviceName, NULL, NULL);
56       }
57       else {
58         i_push_errorf(0, "Cannot enumerate device %d: %ld", display, (long)GetLastError());
59         return NULL;
60       }
61
62       window_width = GetDeviceCaps(cdc, HORZRES);
63       window_height = GetDeviceCaps(cdc, VERTRES);
64     }
65
66     wdc = cdc;
67   }
68
69   /* adjust negative/zero values to window size */
70   if (left < 0)
71     left += window_width;
72   if (top < 0)
73     top += window_height;
74   if (right <= 0)
75     right += window_width;
76   if (bottom <= 0)
77     bottom += window_height;
78   
79   /* clamp */
80   if (left < 0)
81     left = 0;
82   if (right > window_width)
83     right = window_width;
84   if (top < 0)
85     top = 0;
86   if (bottom > window_height)
87     bottom = window_height;
88
89   /* validate */
90   if (right <= left || bottom <= top) {
91     i_push_error(0, "image would be empty");
92     return NULL;
93   }
94   width = right - left;
95   height = bottom - top;
96
97   work_bmp = CreateCompatibleBitmap(wdc, width, height);
98   bmdc = CreateCompatibleDC(wdc);
99   old_dc_bmp = SelectObject(bmdc, work_bmp);
100   BitBlt(bmdc, 0, 0, width, height, wdc, orig_x + left, orig_y + top, SRCCOPY);
101
102   /* make a dib */
103   memset(&bmi, 0, sizeof(bmi));
104   bmi.bmiHeader.biSize = sizeof(bmi);
105   bmi.bmiHeader.biWidth = width;
106   bmi.bmiHeader.biHeight = -height;
107   bmi.bmiHeader.biPlanes = 1;
108   bmi.bmiHeader.biBitCount = 32;
109   bmi.bmiHeader.biCompression = BI_RGB;
110
111   di_bits = mymalloc(4 * width * height);
112   if (GetDIBits(bmdc, work_bmp, 0, height, di_bits, &bmi, DIB_RGB_COLORS)) {
113     i_color *line = mymalloc(sizeof(i_color) * width);
114     i_color *cp;
115     int x, y;
116     unsigned char *ch_pp = di_bits;
117     result = i_img_8_new(width, height, 3);
118
119     for (y = 0; y < height; ++y) {
120       cp = line;
121       for (x = 0; x < width; ++x) {
122         cp->rgb.b = *ch_pp++;
123         cp->rgb.g = *ch_pp++;
124         cp->rgb.r = *ch_pp++;
125         ch_pp++;
126         cp++;
127       }
128       i_plin(result, 0, width, y, line);
129     }
130     myfree(line);
131   }
132
133   i_tags_setn(&result->tags, "ss_window_width", window_width);
134   i_tags_setn(&result->tags, "ss_window_height", window_height);
135   i_tags_set(&result->tags, "ss_type", "Win32", 5);
136   i_tags_setn(&result->tags, "ss_left", left);
137   i_tags_setn(&result->tags, "ss_top", top);
138
139   /* clean up */
140   myfree(di_bits);
141   SelectObject(bmdc, old_dc_bmp);
142   DeleteDC(bmdc);
143   DeleteObject(work_bmp);
144
145   if (cdc) {
146     DeleteDC(cdc);
147   }
148   else {
149     ReleaseDC(hwnd, wdc);
150   }
151
152   return result;
153 }