1 #include "main.h"
2
3 #include "../debug.h"
4 #include "../flist.h"
5 #include "../friend.h"
6 #include "../stb.h"
7 #include "../tox.h"
8
9 #include "../av/utox_av.h"
10
11 #include <windowsx.h>
12
13 static HWND grab_window;
14 static HINSTANCE grab_instance;
15 static bool desktopgrab_video = false;
16
17 // creates an UTOX_NATIVE image based on given arguments
18 // image should be freed with image_free
create_utox_image(HBITMAP bmp,bool has_alpha,uint32_t width,uint32_t height)19 static NATIVE_IMAGE *create_utox_image(HBITMAP bmp, bool has_alpha, uint32_t width, uint32_t height) {
20 NATIVE_IMAGE *image = malloc(sizeof(NATIVE_IMAGE));
21 if (!image) {
22 LOG_ERR("NATIVE Screengrab", "create_utox_image:\t Could not allocate memory for image.");
23 return NULL;
24 }
25
26 image->bitmap = bmp;
27 image->has_alpha = has_alpha;
28 image->width = width;
29 image->height = height;
30 image->scaled_width = width;
31 image->scaled_height = height;
32 image->stretch_mode = COLORONCOLOR;
33
34 return image;
35 }
36
sendbitmap(HDC mem,HBITMAP hbm,int width,int height)37 static void sendbitmap(HDC mem, HBITMAP hbm, int width, int height) {
38 if (width == 0 || height == 0) {
39 return;
40 }
41
42 BITMAPINFO info = {
43 .bmiHeader = {
44 .biSize = sizeof(BITMAPINFOHEADER),
45 .biWidth = width,
46 .biHeight = -height,
47 .biPlanes = 1,
48 .biBitCount = 24,
49 .biCompression = BI_RGB,
50 }
51 };
52
53 void *bits = malloc((width + 3) * height * 3);
54
55 GetDIBits(mem, hbm, 0, height, bits, &info, DIB_RGB_COLORS);
56
57 uint8_t pbytes = width & 3, *p = bits, *pp = bits, *end = p + width * height * 3;
58 // uint32_t offset = 0;
59 while (p != end) {
60 int i;
61 for (i = 0; i != width; i++) {
62 uint8_t b = pp[i * 3];
63 p[i * 3] = pp[i * 3 + 2];
64 p[i * 3 + 1] = pp[i * 3 + 1];
65 p[i * 3 + 2] = b;
66 }
67 p += width * 3;
68 pp += width * 3 + pbytes;
69 }
70
71 int size = 0;
72 UTOX_IMAGE out = stbi_write_png_to_mem(bits, 0, width, height, 3, &size);
73
74 free(bits);
75
76 NATIVE_IMAGE *image = create_utox_image(hbm, 0, width, height);
77 friend_sendimage(flist_get_friend(), image, width, height, out, size);
78 }
79
screen_grab_sys(HWND window,UINT msg,WPARAM wParam,LPARAM lParam)80 static LRESULT CALLBACK screen_grab_sys(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {
81 POINT p = {.x = GET_X_LPARAM(lParam), .y = GET_Y_LPARAM(lParam) };
82
83 ClientToScreen(window, &p);
84
85 static bool mdown = false;
86 switch (msg) {
87 case WM_MOUSEMOVE: {
88 if (!mdown) {
89 break;
90 }
91
92 HDC dc = GetDC(window);
93 BitBlt(dc, video_grab_x, video_grab_y, video_grab_w - video_grab_x, video_grab_h - video_grab_y, dc,
94 video_grab_x, video_grab_y, BLACKNESS);
95 video_grab_w = p.x;
96 video_grab_h = p.y;
97 BitBlt(dc, video_grab_x, video_grab_y, video_grab_w - video_grab_x, video_grab_h - video_grab_y, dc,
98 video_grab_x, video_grab_y, WHITENESS);
99 ReleaseDC(window, dc);
100 return false;
101 }
102
103 case WM_LBUTTONDOWN: {
104 mdown = true;
105 video_grab_x = video_grab_w = p.x;
106 video_grab_y = video_grab_h = p.y;
107 SetCapture(window);
108 return false;
109 }
110
111 case WM_LBUTTONUP: {
112 mdown = false;
113 ReleaseCapture();
114
115 if (video_grab_x < video_grab_w) {
116 video_grab_w -= video_grab_x;
117 } else {
118 const int w = video_grab_x - video_grab_w;
119 video_grab_x = video_grab_w;
120 video_grab_w = w;
121 }
122
123 if (video_grab_y < video_grab_h) {
124 video_grab_h -= video_grab_y;
125 } else {
126 const int h = video_grab_y - video_grab_h;
127 video_grab_y = video_grab_h;
128 video_grab_h = h;
129 }
130
131 if (desktopgrab_video) {
132 DestroyWindow(window);
133 postmessage_utoxav(UTOXAV_SET_VIDEO_IN, 1, 0, NULL);
134 } else {
135 if (flist_get_friend()) {
136 FRIEND *f = flist_get_friend();
137 if (f->online) {
138 DestroyWindow(window);
139 HWND dwnd = GetDesktopWindow();
140 HDC ddc = GetDC(dwnd);
141 HDC mem = CreateCompatibleDC(ddc);
142
143 HBITMAP capture = CreateCompatibleBitmap(ddc, video_grab_w, video_grab_h);
144 SelectObject(mem, capture);
145
146 BitBlt(mem, 0, 0, video_grab_w, video_grab_h, ddc, video_grab_x, video_grab_y, SRCCOPY | CAPTUREBLT);
147 sendbitmap(mem, capture, video_grab_w, video_grab_h);
148
149 ReleaseDC(dwnd, ddc);
150 DeleteDC(mem);
151 }
152 }
153 }
154 return false;
155 }
156 }
157
158 return DefWindowProcW(window, msg, wParam, lParam);
159 }
160
screen_grab_init(HINSTANCE app_instance)161 void screen_grab_init(HINSTANCE app_instance) {
162 HICON screengrab_black_icon = LoadIcon(app_instance, MAKEINTRESOURCE(101));
163 wchar_t screen_grab_class[] = L"uToxgrab";
164
165 WNDCLASSW grab_window_class = {
166 .hInstance = app_instance,
167 .lpfnWndProc = screen_grab_sys,
168 .lpszClassName = screen_grab_class,
169 .hIcon = screengrab_black_icon,
170 .hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH),
171 };
172 RegisterClassW(&grab_window_class);
173
174 grab_instance = app_instance;
175 }
176
native_screen_grab_desktop(bool video)177 void native_screen_grab_desktop(bool video) {
178 int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
179 int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
180 int w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
181 int h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
182
183 LOG_TRACE("Native Screengrab", "result: %i %i %i %i" , x, y, w, h);
184
185 grab_window = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_LAYERED, L"uToxgrab", L"Tox", WS_POPUP,
186 x, y, w, h,
187 NULL, NULL, grab_instance, NULL);
188 if (!grab_window) {
189 LOG_TRACE("Native Screengrab", "CreateWindowExW() failed" );
190 return;
191 }
192
193 SetLayeredWindowAttributes(grab_window, 0xFFFFFF, 128, LWA_ALPHA | LWA_COLORKEY);
194 // UpdateLayeredWindow(main_window.window, NULL, NULL, NULL, NULL, NULL, 0xFFFFFF, ULW_ALPHA | ULW_COLORKEY);
195
196 ShowWindow(grab_window, SW_SHOW);
197 SetForegroundWindow(grab_window);
198
199 desktopgrab_video = video;
200 }
201