Line |
Branch |
Exec |
Source |
1 |
|
|
/* GATE PROJECT LICENSE: |
2 |
|
|
+----------------------------------------------------------------------------+ |
3 |
|
|
| Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> | |
4 |
|
|
| All rights reserved. | |
5 |
|
|
| | |
6 |
|
|
| Redistribution and use in source and binary forms, with or without | |
7 |
|
|
| modification, are permitted provided that the following conditions are met:| |
8 |
|
|
| | |
9 |
|
|
| 1. Redistributions of source code must retain the above copyright notice, | |
10 |
|
|
| this list of conditions and the following disclaimer. | |
11 |
|
|
| 2. Redistributions in binary form must reproduce the above copyright | |
12 |
|
|
| notice, this list of conditions and the following disclaimer in the | |
13 |
|
|
| documentation and/or other materials provided with the distribution. | |
14 |
|
|
| | |
15 |
|
|
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| |
16 |
|
|
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
17 |
|
|
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
18 |
|
|
| ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
19 |
|
|
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
20 |
|
|
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
21 |
|
|
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
22 |
|
|
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
23 |
|
|
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
24 |
|
|
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
25 |
|
|
| THE POSSIBILITY OF SUCH DAMAGE. | |
26 |
|
|
+----------------------------------------------------------------------------+ |
27 |
|
|
*/ |
28 |
|
|
#include "gate/io/videosources.h" |
29 |
|
|
#include "gate/platforms.h" |
30 |
|
|
#include "gate/results.h" |
31 |
|
|
|
32 |
|
|
#if defined(GATE_SYS_WIN) |
33 |
|
|
# if defined(GATE_SYS_WINSTORE) || defined(GATE_SYS_WIN16) |
34 |
|
|
# define GATE_IO_VIDEO_NO_IMPL |
35 |
|
|
# else |
36 |
|
|
# define GATE_IO_VIDEO_WINAPI |
37 |
|
|
# define GATE_IO_VIDEO_SCREEN_INTERFACE |
38 |
|
|
# endif |
39 |
|
|
#elif defined(GATE_SYS_ANDROID) |
40 |
|
|
# define GATE_IO_VIDEO_ANDROID |
41 |
|
|
#elif defined(GATE_SYS_LINUX) |
42 |
|
|
# define GATE_IO_VIDEO_X11 |
43 |
|
|
# define GATE_IO_VIDEO_SCREEN_INTERFACE |
44 |
|
|
#else |
45 |
|
|
# define GATE_IO_VIDEO_NO_IMPL |
46 |
|
|
#endif |
47 |
|
|
|
48 |
|
|
|
49 |
|
|
|
50 |
|
|
#if defined(GATE_IO_VIDEO_SCREEN_INTERFACE) |
51 |
|
|
|
52 |
|
|
static char const* screenctrl_get_interface_name(void* thisptr); |
53 |
|
|
static void screenctrl_release(void* thisptr); |
54 |
|
|
static int screenctrl_retain(void* thisptr); |
55 |
|
|
|
56 |
|
|
static char const* screenctrl_get_id(void* thisptr); |
57 |
|
|
static char const* screenctrl_get_name(void* thisptr); |
58 |
|
|
static gate_intptr_t screenctrl_get_handle(void* thisptr); |
59 |
|
|
static gate_size_t screenctrl_get_supported_formats(void* thisptr, gate_video_format_t* format_buffer, gate_size_t format_buffer_count); |
60 |
|
|
|
61 |
|
|
static gate_result_t screenctrl_open(void* thisptr, gate_video_format_t const* format); |
62 |
|
|
static gate_result_t screenctrl_close(void* thisptr); |
63 |
|
|
|
64 |
|
|
static gate_result_t screenctrl_read(void* thisptr, gate_video_frame_t* frame); |
65 |
|
|
|
66 |
|
|
static gate_result_t screenctrl_get_cursor_pos(void* thisptr, gate_int32_t* ptr_x, gate_int32_t* ptr_y); |
67 |
|
|
static gate_result_t screenctrl_move_cursor(void* thisptr, gate_int32_t x, gate_int32_t y); |
68 |
|
|
static gate_result_t screenctrl_change_cursor_button_state(void* thisptr, gate_int32_t x, gate_int32_t y, gate_enumint_t button_id, gate_enumint_t button_state); |
69 |
|
|
static gate_result_t screenctrl_change_key_state(void* thisptr, gate_input_keycode_t key_code, gate_enumint_t key_state); |
70 |
|
|
|
71 |
|
✗ |
static GATE_INTERFACE_VTBL(gate_video_screencontrol) const* init_video_screencontrol_vtbl() |
72 |
|
|
{ |
73 |
|
|
static GATE_INTERFACE_VTBL(gate_video_screencontrol) global_vtbl; |
74 |
|
✗ |
if (global_vtbl.get_interface_name == NULL) |
75 |
|
|
{ |
76 |
|
|
GATE_INTERFACE_VTBL(gate_video_screencontrol) const local_vtbl = |
77 |
|
|
{ |
78 |
|
|
&screenctrl_get_interface_name, |
79 |
|
|
&screenctrl_release, |
80 |
|
|
&screenctrl_retain, |
81 |
|
|
|
82 |
|
|
&screenctrl_read, |
83 |
|
|
|
84 |
|
|
&screenctrl_get_id, |
85 |
|
|
&screenctrl_get_name, |
86 |
|
|
&screenctrl_get_handle, |
87 |
|
|
&screenctrl_get_supported_formats, |
88 |
|
|
|
89 |
|
|
&screenctrl_open, |
90 |
|
|
&screenctrl_close, |
91 |
|
|
|
92 |
|
|
&screenctrl_get_cursor_pos, |
93 |
|
|
&screenctrl_move_cursor, |
94 |
|
|
&screenctrl_change_cursor_button_state, |
95 |
|
|
&screenctrl_change_key_state |
96 |
|
|
}; |
97 |
|
✗ |
global_vtbl = local_vtbl; |
98 |
|
|
} |
99 |
|
|
|
100 |
|
✗ |
return &global_vtbl; |
101 |
|
|
} |
102 |
|
|
|
103 |
|
|
#endif |
104 |
|
|
|
105 |
|
|
|
106 |
|
|
#if defined(GATE_IO_VIDEO_WINAPI) |
107 |
|
|
|
108 |
|
|
#include "gate/debugging.h" |
109 |
|
|
#include "gate/graphics/platform/win32_gdi.h" |
110 |
|
|
|
111 |
|
|
#if !defined(GATE_SYS_WINCE) |
112 |
|
|
#define GATE_USE_NT_DESKTOP_API 1 |
113 |
|
|
#endif |
114 |
|
|
|
115 |
|
|
typedef struct win32screen_class |
116 |
|
|
{ |
117 |
|
|
GATE_INTERFACE_VTBL(gate_video_screencontrol) const* vtbl; |
118 |
|
|
|
119 |
|
|
gate_atomic_int_t ref_counter; |
120 |
|
|
|
121 |
|
|
unsigned x; |
122 |
|
|
unsigned y; |
123 |
|
|
unsigned width; |
124 |
|
|
unsigned height; |
125 |
|
|
unsigned bits_per_pixel; |
126 |
|
|
unsigned line_len; |
127 |
|
|
|
128 |
|
|
void* hdesk; |
129 |
|
|
TCHAR deskname[128]; |
130 |
|
|
gate_size_t deskname_length; |
131 |
|
|
|
132 |
|
|
HDC hscreen; |
133 |
|
|
HDC hdc; |
134 |
|
|
HGDIOBJ hbmp_backup; |
135 |
|
|
HBITMAP hbmp; |
136 |
|
|
void* bitmap_bits; |
137 |
|
|
gate_size_t bitmap_bits_length; |
138 |
|
|
|
139 |
|
|
} win32screen_t; |
140 |
|
|
|
141 |
|
|
typedef struct |
142 |
|
|
{ |
143 |
|
|
BITMAPINFO info; |
144 |
|
|
RGBQUAD colors[256]; |
145 |
|
|
} BITMAPINFO_PAL; |
146 |
|
|
|
147 |
|
|
static unsigned init_bmp_pal(RGBQUAD* pal) |
148 |
|
|
{ |
149 |
|
|
gate_color_rgb_t gate_pal[256]; |
150 |
|
|
unsigned pal_len = (unsigned)gate_color_palette_rgb8_create(gate_pal); |
151 |
|
|
unsigned ndx = 0; |
152 |
|
|
for (; ndx != pal_len; ++ndx) |
153 |
|
|
{ |
154 |
|
|
pal[ndx].rgbRed = gate_pal[ndx].r; |
155 |
|
|
pal[ndx].rgbGreen = gate_pal[ndx].g; |
156 |
|
|
pal[ndx].rgbBlue = gate_pal[ndx].b; |
157 |
|
|
pal[ndx].rgbReserved = 0; |
158 |
|
|
} |
159 |
|
|
return pal_len; |
160 |
|
|
} |
161 |
|
|
|
162 |
|
|
static gate_bool_t win32_open_screen(win32screen_t* self) |
163 |
|
|
{ |
164 |
|
|
gate_win32_userapi_t* const user32 = gate_win32_userapi(); |
165 |
|
|
gate_result_t succeeded = false; |
166 |
|
|
HDC screen = NULL; |
167 |
|
|
HDC mem = NULL; |
168 |
|
|
HBITMAP bmp = NULL; |
169 |
|
|
void* bits = NULL; |
170 |
|
|
BITMAPINFO_PAL bmpinfo_pal; |
171 |
|
|
BITMAPINFOHEADER* hdr = &bmpinfo_pal.info.bmiHeader; |
172 |
|
|
RGBQUAD* ptr_rgb; |
173 |
|
|
|
174 |
|
|
do |
175 |
|
|
{ |
176 |
|
|
if (!user32) break; |
177 |
|
|
|
178 |
|
|
screen = user32->UserGetDC(NULL); |
179 |
|
|
if (!screen) break; |
180 |
|
|
|
181 |
|
|
mem = gdi.GdiCreateCompatibleDC(screen); |
182 |
|
|
if (!mem) break; |
183 |
|
|
|
184 |
|
|
gate_mem_clear(&bmpinfo_pal, sizeof(bmpinfo_pal)); |
185 |
|
|
hdr->biSize = sizeof(BITMAPINFOHEADER); |
186 |
|
|
hdr->biWidth = (LONG)self->width; |
187 |
|
|
hdr->biHeight = (LONG)self->height; |
188 |
|
|
hdr->biPlanes = 1; |
189 |
|
|
hdr->biBitCount = self->bits_per_pixel; |
190 |
|
|
hdr->biCompression = BI_RGB; |
191 |
|
|
hdr->biSizeImage = 0; |
192 |
|
|
hdr->biXPelsPerMeter = 0; |
193 |
|
|
hdr->biYPelsPerMeter = 0; |
194 |
|
|
hdr->biClrImportant = 0; |
195 |
|
|
hdr->biClrUsed = 0; |
196 |
|
|
|
197 |
|
|
if (self->bits_per_pixel == 1) |
198 |
|
|
{ |
199 |
|
|
hdr->biClrUsed = 2; |
200 |
|
|
ptr_rgb = &bmpinfo_pal.info.bmiColors[0]; |
201 |
|
|
ptr_rgb->rgbBlue = ptr_rgb->rgbGreen = ptr_rgb->rgbRed = ptr_rgb->rgbReserved = 0; |
202 |
|
|
ptr_rgb = &bmpinfo_pal.info.bmiColors[1]; |
203 |
|
|
ptr_rgb->rgbBlue = ptr_rgb->rgbGreen = ptr_rgb->rgbRed = 255; |
204 |
|
|
ptr_rgb->rgbReserved = 0; |
205 |
|
|
} |
206 |
|
|
else if (self->bits_per_pixel == 8) |
207 |
|
|
{ |
208 |
|
|
hdr->biClrUsed = init_bmp_pal(&bmpinfo_pal.info.bmiColors[0]); |
209 |
|
|
} |
210 |
|
|
bmp = gdi.GdiCreateDIBSection(screen, &bmpinfo_pal.info, DIB_RGB_COLORS, &bits, NULL, 0); |
211 |
|
|
if (NULL == bmp) break; |
212 |
|
|
|
213 |
|
|
/* success-case: */ |
214 |
|
|
self->hscreen = screen; |
215 |
|
|
self->hbmp_backup = gdi.GdiSelectObject(mem, (HGDIOBJ)bmp); |
216 |
|
|
self->hdc = mem; |
217 |
|
|
self->hbmp = bmp; |
218 |
|
|
self->bitmap_bits = bits; |
219 |
|
|
succeeded = true; |
220 |
|
|
} while (0); |
221 |
|
|
|
222 |
|
|
if (!succeeded) |
223 |
|
|
{ |
224 |
|
|
if (mem) gdi.GdiDeleteDC(mem); |
225 |
|
|
if (screen) user32->UserReleaseDC(NULL, screen); |
226 |
|
|
} |
227 |
|
|
return succeeded; |
228 |
|
|
} |
229 |
|
|
|
230 |
|
|
static void win32_close_screen(win32screen_t* self) |
231 |
|
|
{ |
232 |
|
|
if (self->hdc) |
233 |
|
|
{ |
234 |
|
|
gdi.GdiSelectObject(self->hdc, self->hbmp_backup); |
235 |
|
|
gdi.GdiDeleteObject((HGDIOBJ)self->hbmp); |
236 |
|
|
gdi.GdiDeleteDC(self->hdc); |
237 |
|
|
gdi.GdiDeleteDC(self->hscreen); |
238 |
|
|
self->hbmp_backup = NULL; |
239 |
|
|
self->hbmp = NULL; |
240 |
|
|
self->hdc = NULL; |
241 |
|
|
} |
242 |
|
|
|
243 |
|
|
if (self->hscreen) |
244 |
|
|
{ |
245 |
|
|
self->hscreen = NULL; |
246 |
|
|
} |
247 |
|
|
} |
248 |
|
|
|
249 |
|
|
#if defined(GATE_USE_NT_DESKTOP_API) |
250 |
|
|
|
251 |
|
|
static gate_size_t win32_get_desktop_name(void* hdesk, TCHAR* desktop_name_buffer, gate_size_t desktop_name_buffer_capacity) |
252 |
|
|
{ |
253 |
|
|
gate_win32_userapi_t* const user32 = gate_win32_userapi(); |
254 |
|
|
DWORD bytes_needed; |
255 |
|
|
|
256 |
|
|
if (!user32 || !user32->UserGetUserObjectInformation || |
257 |
|
|
!user32->UserGetUserObjectInformation(hdesk, UOI_NAME, desktop_name_buffer, (DWORD)desktop_name_buffer_capacity * sizeof(TCHAR), &bytes_needed)) |
258 |
|
|
{ |
259 |
|
|
/* api not available, or failed */ |
260 |
|
|
return 0; |
261 |
|
|
} |
262 |
|
|
return bytes_needed / sizeof(TCHAR); |
263 |
|
|
} |
264 |
|
|
|
265 |
|
|
static gate_bool_t win32_open_input_desktop(void** ptr_hdesk, TCHAR* ptr_deskname, gate_size_t* ptr_deskname_length) |
266 |
|
|
{ |
267 |
|
|
gate_win32_userapi_t* const user32 = gate_win32_userapi(); |
268 |
|
|
void* hdesk; |
269 |
|
|
|
270 |
|
|
if (!user32 || !user32->UserOpenInputDesktop) |
271 |
|
|
{ |
272 |
|
|
return false; |
273 |
|
|
} |
274 |
|
|
|
275 |
|
|
hdesk = user32->UserOpenInputDesktop(0, FALSE, GENERIC_ALL); |
276 |
|
|
if (hdesk == NULL) |
277 |
|
|
{ |
278 |
|
|
return false; |
279 |
|
|
} |
280 |
|
|
*ptr_deskname_length = win32_get_desktop_name(hdesk, ptr_deskname, *ptr_deskname_length); |
281 |
|
|
*ptr_hdesk = hdesk; |
282 |
|
|
return true; |
283 |
|
|
} |
284 |
|
|
|
285 |
|
|
static void win32_close_desktop(void** hdesk) |
286 |
|
|
{ |
287 |
|
|
if (*hdesk) |
288 |
|
|
{ |
289 |
|
|
gate_win32_userapi_t* const user32 = gate_win32_userapi(); |
290 |
|
|
user32->UserCloseDesktop((HDESK)*hdesk); |
291 |
|
|
*hdesk = NULL; |
292 |
|
|
} |
293 |
|
|
} |
294 |
|
|
|
295 |
|
|
static gate_bool_t win32_are_desktops_equal(void* desk1, TCHAR const* desk1name, gate_size_t desk1name_len, void* desk2, TCHAR const* desk2name, gate_size_t desk2name_len) |
296 |
|
|
{ |
297 |
|
|
if (desk1 == desk2) |
298 |
|
|
{ |
299 |
|
|
return true; |
300 |
|
|
} |
301 |
|
|
if (desk1name_len != desk2name_len) |
302 |
|
|
{ |
303 |
|
|
return false; |
304 |
|
|
} |
305 |
|
|
else |
306 |
|
|
{ |
307 |
|
|
return 0 == gate_win32_winstr_comp_range(desk1name, desk2name, desk1name_len); |
308 |
|
|
} |
309 |
|
|
} |
310 |
|
|
|
311 |
|
|
static gate_bool_t win32_change_thread_desktop(void* target_desktop) |
312 |
|
|
{ |
313 |
|
|
gate_win32_userapi_t* const user32 = gate_win32_userapi(); |
314 |
|
|
if (!user32 || !user32->UserSetThreadDesktop |
315 |
|
|
|| !user32->UserSetThreadDesktop((HDESK)target_desktop)) |
316 |
|
|
{ |
317 |
|
|
GATE_DEBUG_TRACE("SetThreadDesktop() failed"); |
318 |
|
|
return false; |
319 |
|
|
} |
320 |
|
|
return true; |
321 |
|
|
} |
322 |
|
|
|
323 |
|
|
static gate_bool_t screenctrl_update_desktop(win32screen_t* self) |
324 |
|
|
{ |
325 |
|
|
void* input_hdesk = NULL; |
326 |
|
|
TCHAR input_deskname[128]; |
327 |
|
|
gate_size_t input_deskname_len = sizeof(input_deskname) / sizeof(input_deskname[0]); |
328 |
|
|
gate_bool_t result = win32_open_input_desktop(&input_hdesk, input_deskname, &input_deskname_len); |
329 |
|
|
if (!result) |
330 |
|
|
{ |
331 |
|
|
GATE_DEBUG_TRACE("Failed to open input desktop"); |
332 |
|
|
return false; |
333 |
|
|
} |
334 |
|
|
result = win32_are_desktops_equal(self->hdesk, self->deskname, self->deskname_length, input_hdesk, input_deskname, input_deskname_len); |
335 |
|
|
if (result) |
336 |
|
|
{ |
337 |
|
|
/* desktops are equal, no change required */ |
338 |
|
|
win32_close_desktop(&input_hdesk); |
339 |
|
|
return true; |
340 |
|
|
} |
341 |
|
|
/* switch to new desktop */ |
342 |
|
|
result = win32_change_thread_desktop(input_hdesk); |
343 |
|
|
if (!result) |
344 |
|
|
{ |
345 |
|
|
GATE_DEBUG_TRACE("Failed to switch thread-desktop"); |
346 |
|
|
win32_close_desktop(&input_hdesk); |
347 |
|
|
return false; |
348 |
|
|
} |
349 |
|
|
/* close old desktop handle and screen objects */ |
350 |
|
|
win32_close_screen(self); |
351 |
|
|
win32_close_desktop(&self->hdesk); |
352 |
|
|
/* install new desktop handle */ |
353 |
|
|
self->hdesk = input_hdesk; |
354 |
|
|
gate_mem_copy(&self->deskname[0], input_deskname, input_deskname_len * sizeof(TCHAR)); |
355 |
|
|
self->deskname_length = input_deskname_len; |
356 |
|
|
self->deskname[self->deskname_length] = 0; |
357 |
|
|
return true; |
358 |
|
|
} |
359 |
|
|
|
360 |
|
|
#endif /* GATE_USE_NT_DESKTOP_API */ |
361 |
|
|
|
362 |
|
|
|
363 |
|
|
static gate_bool_t screenctrl_is_screen_opened(win32screen_t* self) |
364 |
|
|
{ |
365 |
|
|
return (self->hscreen != NULL) && (self->hdc != NULL) && (self->hbmp != NULL); |
366 |
|
|
} |
367 |
|
|
|
368 |
|
|
|
369 |
|
|
static void screenctrl_destroy(win32screen_t* self) |
370 |
|
|
{ |
371 |
|
|
win32_close_screen(self); |
372 |
|
|
#if defined(GATE_USE_NT_DESKTOP_API) |
373 |
|
|
win32_close_desktop(&self->hdesk); |
374 |
|
|
#endif |
375 |
|
|
} |
376 |
|
|
|
377 |
|
|
static char const* screenctrl_get_interface_name(void* thisptr) |
378 |
|
|
{ |
379 |
|
|
return GATE_INTERFACE_NAME_VIDEO_SOURCE_SCREENCONTROL; |
380 |
|
|
} |
381 |
|
|
|
382 |
|
|
static void screenctrl_release(void* thisptr) |
383 |
|
|
{ |
384 |
|
|
win32screen_t* const self = (win32screen_t*)thisptr; |
385 |
|
|
if (gate_atomic_int_dec(&self->ref_counter) == 0) |
386 |
|
|
{ |
387 |
|
|
screenctrl_destroy(self); |
388 |
|
|
} |
389 |
|
|
} |
390 |
|
|
static int screenctrl_retain(void* thisptr) |
391 |
|
|
{ |
392 |
|
|
win32screen_t* const self = (win32screen_t*)thisptr; |
393 |
|
|
return gate_atomic_int_inc(&self->ref_counter); |
394 |
|
|
} |
395 |
|
|
|
396 |
|
|
static char const* screenctrl_get_id(void* thisptr) |
397 |
|
|
{ |
398 |
|
|
return "screen"; |
399 |
|
|
} |
400 |
|
|
static char const* screenctrl_get_name(void* thisptr) |
401 |
|
|
{ |
402 |
|
|
return "screen"; |
403 |
|
|
} |
404 |
|
|
static gate_intptr_t screenctrl_get_handle(void* thisptr) |
405 |
|
|
{ |
406 |
|
|
win32screen_t* const self = (win32screen_t*)thisptr; |
407 |
|
|
return (gate_intptr_t)self->hscreen; |
408 |
|
|
} |
409 |
|
|
|
410 |
|
|
#ifndef SM_CXVIRTUALSCREEN |
411 |
|
|
#define SM_CXVIRTUALSCREEN 78 |
412 |
|
|
#endif |
413 |
|
|
|
414 |
|
|
#ifndef SM_CYVIRTUALSCREEN |
415 |
|
|
#define SM_CYVIRTUALSCREEN 79 |
416 |
|
|
#endif |
417 |
|
|
|
418 |
|
|
static gate_size_t screenctrl_get_supported_formats(void* thisptr, gate_video_format_t* format_buffer, gate_size_t format_buffer_count) |
419 |
|
|
{ |
420 |
|
|
gate_win32_userapi_t* const user32 = gate_win32_userapi(); |
421 |
|
|
win32screen_t* const self = (win32screen_t*)thisptr; |
422 |
|
|
int sx, sy; |
423 |
|
|
|
424 |
|
|
if ((format_buffer_count == 0) || (format_buffer == NULL)) |
425 |
|
|
{ |
426 |
|
|
return 0; |
427 |
|
|
} |
428 |
|
|
|
429 |
|
|
sx = user32->UserGetSystemMetrics(SM_CXVIRTUALSCREEN); |
430 |
|
|
sy = user32->UserGetSystemMetrics(SM_CYVIRTUALSCREEN); |
431 |
|
|
if (sx == 0) sx = user32->UserGetSystemMetrics(SM_CXSCREEN); |
432 |
|
|
if (sy == 0) sy = user32->UserGetSystemMetrics(SM_CYSCREEN); |
433 |
|
|
|
434 |
|
|
format_buffer->encoding_id = 0; |
435 |
|
|
format_buffer->compression = 0; |
436 |
|
|
format_buffer->frames_per_second = 5.0f; |
437 |
|
|
format_buffer->width = sx; |
438 |
|
|
format_buffer->height = sy; |
439 |
|
|
format_buffer->bits_per_pixel = 24; |
440 |
|
|
|
441 |
|
|
return 1; |
442 |
|
|
} |
443 |
|
|
|
444 |
|
|
static gate_bool_t screenctrl_is_opened(win32screen_t* self) |
445 |
|
|
{ |
446 |
|
|
if ((self->width == 0) || (self->height == 0) || (self->bits_per_pixel == 0)) |
447 |
|
|
{ |
448 |
|
|
return false; |
449 |
|
|
} |
450 |
|
|
return true; |
451 |
|
|
} |
452 |
|
|
|
453 |
|
|
static gate_result_t screenctrl_open(void* thisptr, gate_video_format_t const* format) |
454 |
|
|
{ |
455 |
|
|
win32screen_t* const self = (win32screen_t*)thisptr; |
456 |
|
|
|
457 |
|
|
if (screenctrl_is_opened(self)) |
458 |
|
|
{ |
459 |
|
|
return GATE_RESULT_INVALIDSTATE; |
460 |
|
|
} |
461 |
|
|
|
462 |
|
|
if ((NULL == format) || (format->width == 0) || (format->height == 0)) |
463 |
|
|
{ |
464 |
|
|
return GATE_RESULT_INVALIDARG; |
465 |
|
|
} |
466 |
|
|
|
467 |
|
|
switch (format->bits_per_pixel) |
468 |
|
|
{ |
469 |
|
|
case 1: |
470 |
|
|
case 8: |
471 |
|
|
case 16: |
472 |
|
|
case 24: |
473 |
|
|
self->bits_per_pixel = format->bits_per_pixel; |
474 |
|
|
break; |
475 |
|
|
default: |
476 |
|
|
self->bits_per_pixel = 24; |
477 |
|
|
break; |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
self->x = 0; |
481 |
|
|
self->y = 0; |
482 |
|
|
self->width = format->width; |
483 |
|
|
self->height = format->height; |
484 |
|
|
self->line_len = ((self->bits_per_pixel * self->width) / 8 + 3) & 0xfffffffc; |
485 |
|
|
|
486 |
|
|
#if defined(GATE_USE_NT_DESKTOP_API) |
487 |
|
|
screenctrl_update_desktop(self); |
488 |
|
|
#endif |
489 |
|
|
|
490 |
|
|
return GATE_RESULT_OK; |
491 |
|
|
} |
492 |
|
|
|
493 |
|
|
static gate_result_t screenctrl_close(void* thisptr) |
494 |
|
|
{ |
495 |
|
|
win32screen_t* const self = (win32screen_t*)thisptr; |
496 |
|
|
|
497 |
|
|
win32_close_screen(self); |
498 |
|
|
#if defined(GATE_USE_NT_DESKTOP_API) |
499 |
|
|
win32_close_desktop(&self->hdesk); |
500 |
|
|
#endif |
501 |
|
|
|
502 |
|
|
self->width = 0; |
503 |
|
|
self->height = 0; |
504 |
|
|
self->bits_per_pixel; |
505 |
|
|
self->bitmap_bits = NULL; |
506 |
|
|
self->bitmap_bits_length = 0; |
507 |
|
|
|
508 |
|
|
return GATE_RESULT_OK; |
509 |
|
|
} |
510 |
|
|
|
511 |
|
|
static gate_result_t screenctrl_read(void* thisptr, gate_video_frame_t* frame) |
512 |
|
|
{ |
513 |
|
|
win32screen_t* const self = (win32screen_t*)thisptr; |
514 |
|
|
gate_bool_t update_succeeded; |
515 |
|
|
gate_rasterimage_t raster = GATE_INIT_EMPTY; |
516 |
|
|
unsigned y, x; |
517 |
|
|
unsigned char const* ptr_src; |
518 |
|
|
unsigned char* ptr_dst; |
519 |
|
|
|
520 |
|
|
if ((self->width == 0) || (self->height == 0)) |
521 |
|
|
{ |
522 |
|
|
return GATE_RESULT_INVALIDSTATE; |
523 |
|
|
} |
524 |
|
|
|
525 |
|
|
#if defined(GATE_USE_NT_DESKTOP_API) |
526 |
|
|
update_succeeded = screenctrl_update_desktop(self); |
527 |
|
|
if (!update_succeeded) |
528 |
|
|
{ |
529 |
|
|
GATE_DEBUG_TRACE("Failed to update desktop object"); |
530 |
|
|
} |
531 |
|
|
#endif |
532 |
|
|
|
533 |
|
|
if (!screenctrl_is_screen_opened(self)) |
534 |
|
|
{ |
535 |
|
|
if (!win32_open_screen(self)) |
536 |
|
|
{ |
537 |
|
|
GATE_DEBUG_TRACE("Failed to open screen"); |
538 |
|
|
return GATE_RESULT_FAILED; |
539 |
|
|
} |
540 |
|
|
} |
541 |
|
|
|
542 |
|
|
update_succeeded = gdi.GdiBitBlt(self->hdc, 0, 0, self->width, self->height, self->hscreen, self->x, self->y, SRCCOPY); |
543 |
|
|
if (!update_succeeded) |
544 |
|
|
{ |
545 |
|
|
GATE_DEBUG_TRACE("Failed to copy screen into memory buffer"); |
546 |
|
|
return GATE_RESULT_FAILED; |
547 |
|
|
} |
548 |
|
|
|
549 |
|
|
switch (self->bits_per_pixel) |
550 |
|
|
{ |
551 |
|
|
case 1: |
552 |
|
|
{ |
553 |
|
|
if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_PAL8, self->width, self->height, NULL)) |
554 |
|
|
{ |
555 |
|
|
return GATE_RESULT_OUTOFMEMORY; |
556 |
|
|
} |
557 |
|
|
for (y = 0; y != self->height; ++y) |
558 |
|
|
{ |
559 |
|
|
ptr_src = (unsigned char const*)self->bitmap_bits + (self->height - 1 - y) * self->line_len; |
560 |
|
|
ptr_dst = (unsigned char*)gate_rasterimage_get_line_ptr(&raster, y); |
561 |
|
|
for (x = 0; x != self->width; ++x) |
562 |
|
|
{ |
563 |
|
|
gate_uint8_t b = ptr_src[x / 8]; |
564 |
|
|
gate_uint8_t bit = x % 8; |
565 |
|
|
*ptr_dst = ((b & (1 << (7 - bit))) == 0) ? 0 : 15; |
566 |
|
|
++ptr_dst; |
567 |
|
|
} |
568 |
|
|
} |
569 |
|
|
break; |
570 |
|
|
} |
571 |
|
|
case 8: |
572 |
|
|
{ |
573 |
|
|
if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_PAL8, self->width, self->height, NULL)) |
574 |
|
|
{ |
575 |
|
|
return GATE_RESULT_OUTOFMEMORY; |
576 |
|
|
} |
577 |
|
|
for (y = 0; y != self->height; ++y) |
578 |
|
|
{ |
579 |
|
|
ptr_src = (unsigned char const*)self->bitmap_bits + (self->height - 1 - y) * self->line_len; |
580 |
|
|
ptr_dst = (unsigned char*)gate_rasterimage_get_line_ptr(&raster, y); |
581 |
|
|
gate_mem_copy(ptr_dst, ptr_src, self->width); |
582 |
|
|
} |
583 |
|
|
break; |
584 |
|
|
} |
585 |
|
|
case 15: |
586 |
|
|
case 16: |
587 |
|
|
{ |
588 |
|
|
if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_RGB555, self->width, self->height, NULL)) |
589 |
|
|
{ |
590 |
|
|
return GATE_RESULT_OUTOFMEMORY; |
591 |
|
|
} |
592 |
|
|
for (y = 0; y != self->height; ++y) |
593 |
|
|
{ |
594 |
|
|
ptr_src = (unsigned char const*)self->bitmap_bits + (self->height - 1 - y) * self->line_len; |
595 |
|
|
ptr_dst = (unsigned char*)gate_rasterimage_get_line_ptr(&raster, y); |
596 |
|
|
for (x = 0; x != self->width; ++x) |
597 |
|
|
{ |
598 |
|
|
gate_uint8_t const b = (ptr_src[0] & 0x1f) << 3; |
599 |
|
|
gate_uint8_t const g = ((ptr_src[0] >> 5) | ((ptr_src[1] & 0x03) << 3)) << 3; |
600 |
|
|
gate_uint8_t const r = (ptr_src[1] & 0x7c) << 1; |
601 |
|
|
|
602 |
|
|
unsigned const num = ((unsigned)(r >> 3)) << 10 |
603 |
|
|
| ((unsigned)(g >> 3)) << 5 |
604 |
|
|
| ((unsigned)(b >> 3)); |
605 |
|
|
ptr_dst[0] = (gate_uint8_t)(num & 0xff); |
606 |
|
|
ptr_dst[1] = (gate_uint8_t)(num >> 8); |
607 |
|
|
|
608 |
|
|
ptr_src += 2; |
609 |
|
|
ptr_dst += 2; |
610 |
|
|
} |
611 |
|
|
} |
612 |
|
|
break; |
613 |
|
|
} |
614 |
|
|
case 24: |
615 |
|
|
{ |
616 |
|
|
if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_RGB24, self->width, self->height, NULL)) |
617 |
|
|
{ |
618 |
|
|
return GATE_RESULT_OUTOFMEMORY; |
619 |
|
|
} |
620 |
|
|
for (y = 0; y != self->height; ++y) |
621 |
|
|
{ |
622 |
|
|
ptr_src = (unsigned char const*)self->bitmap_bits + (self->height - 1 - y) * self->line_len; |
623 |
|
|
ptr_dst = (unsigned char*)gate_rasterimage_get_line_ptr(&raster, y); |
624 |
|
|
for (x = 0; x != self->width; ++x) |
625 |
|
|
{ |
626 |
|
|
/* BGR to RGB */ |
627 |
|
|
ptr_dst[0] = ptr_src[2]; |
628 |
|
|
ptr_dst[1] = ptr_src[1]; |
629 |
|
|
ptr_dst[2] = ptr_src[0]; |
630 |
|
|
ptr_src += 3; |
631 |
|
|
ptr_dst += 3; |
632 |
|
|
} |
633 |
|
|
} |
634 |
|
|
break; |
635 |
|
|
} |
636 |
|
|
default: |
637 |
|
|
{ |
638 |
|
|
return GATE_RESULT_NOTSUPPORTED; |
639 |
|
|
} |
640 |
|
|
} |
641 |
|
|
|
642 |
|
|
frame->format.encoding_id = 0; |
643 |
|
|
frame->format.compression = 0; |
644 |
|
|
frame->format.frames_per_second = 5.0f; |
645 |
|
|
frame->format.width = self->width; |
646 |
|
|
frame->format.height = self->height; |
647 |
|
|
frame->format.bits_per_pixel = self->bits_per_pixel; |
648 |
|
|
|
649 |
|
|
frame->record_time = 0; |
650 |
|
|
gate_mem_copy(&frame->image, &raster, sizeof(raster)); |
651 |
|
|
return GATE_RESULT_OK; |
652 |
|
|
} |
653 |
|
|
|
654 |
|
|
static gate_result_t win32_send_input(INPUT* inp) |
655 |
|
|
{ |
656 |
|
|
gate_win32_userapi_t* const user32 = gate_win32_userapi(); |
657 |
|
|
UINT result; |
658 |
|
|
|
659 |
|
|
if (!user32) |
660 |
|
|
{ |
661 |
|
|
return GATE_RESULT_NOTAVAILABLE; |
662 |
|
|
} |
663 |
|
|
|
664 |
|
|
if (user32->UserSendInput) |
665 |
|
|
{ |
666 |
|
|
result = user32->UserSendInput(1, inp, sizeof(INPUT)); |
667 |
|
|
if (result != 1) |
668 |
|
|
{ |
669 |
|
|
return GATE_RESULT_FAILED; |
670 |
|
|
} |
671 |
|
|
return GATE_RESULT_OK; |
672 |
|
|
} |
673 |
|
|
|
674 |
|
|
/* win95 NT 3.1 do not support SendInput: */ |
675 |
|
|
if ((inp->type == INPUT_MOUSE) && (user32->UserMouse_event)) |
676 |
|
|
{ |
677 |
|
|
user32->UserMouse_event(inp->mi.dwFlags, inp->mi.dx, inp->mi.dy, inp->mi.mouseData, inp->mi.dwExtraInfo); |
678 |
|
|
return GATE_RESULT_OK; |
679 |
|
|
} |
680 |
|
|
|
681 |
|
|
if ((inp->type == INPUT_KEYBOARD) && (user32->UserKeybd_event)) |
682 |
|
|
{ |
683 |
|
|
user32->UserKeybd_event((BYTE)inp->ki.wVk, (BYTE)inp->ki.wScan, inp->ki.dwFlags, inp->ki.dwExtraInfo); |
684 |
|
|
return GATE_RESULT_OK; |
685 |
|
|
} |
686 |
|
|
|
687 |
|
|
return GATE_RESULT_NOTSUPPORTED; |
688 |
|
|
} |
689 |
|
|
|
690 |
|
|
#ifndef MOUSEEVENTF_VIRTUALDESK |
691 |
|
|
#define MOUSEEVENTF_VIRTUALDESK 0x4000 |
692 |
|
|
#endif |
693 |
|
|
|
694 |
|
|
static void win32_prepare_mouse_input(INPUT* inp, gate_int32_t x, gate_int32_t y) |
695 |
|
|
{ |
696 |
|
|
gate_win32_userapi_t* const user32 = gate_win32_userapi(); |
697 |
|
|
|
698 |
|
|
int screen_width; |
699 |
|
|
int screen_height; |
700 |
|
|
|
701 |
|
|
if (user32) |
702 |
|
|
{ |
703 |
|
|
screen_width = user32->UserGetSystemMetrics(SM_CXVIRTUALSCREEN); |
704 |
|
|
screen_height = user32->UserGetSystemMetrics(SM_CYVIRTUALSCREEN); |
705 |
|
|
if (screen_width == 0) screen_width = user32->UserGetSystemMetrics(SM_CXSCREEN); |
706 |
|
|
if (screen_height == 0) screen_height = user32->UserGetSystemMetrics(SM_CYSCREEN); |
707 |
|
|
inp->mi.dwExtraInfo = user32->UserGetMessageExtraInfo(); |
708 |
|
|
} |
709 |
|
|
else |
710 |
|
|
{ |
711 |
|
|
screen_width = 640; |
712 |
|
|
screen_height = 480; |
713 |
|
|
inp->mi.dwExtraInfo = 0; |
714 |
|
|
} |
715 |
|
|
|
716 |
|
|
inp->type = INPUT_MOUSE; |
717 |
|
|
inp->mi.dx = (screen_width > 0) ? (x * 65536 / screen_width) : 0; |
718 |
|
|
inp->mi.dy = (screen_height > 0) ? (y * 65536 / screen_height) : 0; |
719 |
|
|
inp->mi.mouseData = 0; |
720 |
|
|
inp->mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK; |
721 |
|
|
inp->mi.time = 0; |
722 |
|
|
} |
723 |
|
|
|
724 |
|
|
static gate_result_t screenctrl_get_cursor_pos(void* thisptr, gate_int32_t* ptr_x, gate_int32_t* ptr_y) |
725 |
|
|
{ |
726 |
|
|
gate_win32_userapi_t* const user32 = gate_win32_userapi(); |
727 |
|
|
POINT pnt; |
728 |
|
|
if (!user32) |
729 |
|
|
{ |
730 |
|
|
return GATE_RESULT_FAILED; |
731 |
|
|
} |
732 |
|
|
if (!user32->UserGetCursorPos(&pnt)) |
733 |
|
|
{ |
734 |
|
|
return GATE_RESULT_FAILED; |
735 |
|
|
} |
736 |
|
|
if (ptr_x) *ptr_x = pnt.x; |
737 |
|
|
if (ptr_y) *ptr_y = pnt.y; |
738 |
|
|
return GATE_RESULT_OK; |
739 |
|
|
} |
740 |
|
|
static gate_result_t screenctrl_move_cursor(void* thisptr, gate_int32_t x, gate_int32_t y) |
741 |
|
|
{ |
742 |
|
|
INPUT inp; |
743 |
|
|
win32_prepare_mouse_input(&inp, x, y); |
744 |
|
|
return win32_send_input(&inp); |
745 |
|
|
} |
746 |
|
|
static gate_result_t screenctrl_change_cursor_button_state(void* thisptr, gate_int32_t x, gate_int32_t y, gate_enumint_t button_id, gate_enumint_t button_state) |
747 |
|
|
{ |
748 |
|
|
INPUT inp; |
749 |
|
|
win32_prepare_mouse_input(&inp, x, y); |
750 |
|
|
if (GATE_FLAG_ENABLED(button_state, GATE_VIDEO_SCREENCONTROL_STATE_DOWN)) |
751 |
|
|
{ |
752 |
|
|
/* mouse down */ |
753 |
|
|
if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_LEFT) inp.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN; |
754 |
|
|
if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_MIDDLE) inp.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN; |
755 |
|
|
if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_RIGHT) inp.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN; |
756 |
|
|
} |
757 |
|
|
else if (GATE_FLAG_ENABLED(button_state, GATE_VIDEO_SCREENCONTROL_STATE_UP)) |
758 |
|
|
{ |
759 |
|
|
/* mouse up */ |
760 |
|
|
if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_LEFT) inp.mi.dwFlags |= MOUSEEVENTF_LEFTUP; |
761 |
|
|
if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_MIDDLE) inp.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP; |
762 |
|
|
if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_RIGHT) inp.mi.dwFlags |= MOUSEEVENTF_RIGHTUP; |
763 |
|
|
} |
764 |
|
|
return win32_send_input(&inp); |
765 |
|
|
} |
766 |
|
|
|
767 |
|
|
static gate_input_keystates_t extract_state_keys_from_key_state_flags(gate_enumint_t key_state) |
768 |
|
|
{ |
769 |
|
|
gate_input_keystates_t value = 0; |
770 |
|
|
if (GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_CTRL)) value |= GATE_KBD_KEYSTATE_CTRL; |
771 |
|
|
if (GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_MENU)) value |= GATE_KBD_KEYSTATE_MENU; |
772 |
|
|
if (GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_SHIFT)) value |= GATE_KBD_KEYSTATE_SHIFT; |
773 |
|
|
return value; |
774 |
|
|
} |
775 |
|
|
|
776 |
|
|
static void win32_prepare_key_input(INPUT* inp, gate_input_keycode_t keycode, gate_input_keystates_t keystates, gate_bool_t down) |
777 |
|
|
{ |
778 |
|
|
gate_win32_userapi_t* const user32 = gate_win32_userapi(); |
779 |
|
|
gate_input_nativekeycode_t vk = 0; |
780 |
|
|
|
781 |
|
|
if (user32 && user32->UserGetMessageExtraInfo) |
782 |
|
|
{ |
783 |
|
|
inp->ki.dwExtraInfo = user32->UserGetMessageExtraInfo(); |
784 |
|
|
} |
785 |
|
|
else |
786 |
|
|
{ |
787 |
|
|
inp->ki.dwExtraInfo = 0; |
788 |
|
|
} |
789 |
|
|
|
790 |
|
|
inp->type = INPUT_KEYBOARD; |
791 |
|
|
gate_keyboard_build_native_key(keycode, keystates, &vk); |
792 |
|
|
inp->ki.wVk = (WORD)vk; |
793 |
|
|
inp->ki.wScan = 0; |
794 |
|
|
inp->ki.dwFlags = down ? 0 : KEYEVENTF_KEYUP; |
795 |
|
|
inp->ki.time = 0; |
796 |
|
|
} |
797 |
|
|
|
798 |
|
|
static gate_result_t screenctrl_change_key_state(void* thisptr, gate_input_keycode_t key_code, gate_enumint_t key_state) |
799 |
|
|
{ |
800 |
|
|
INPUT inp; |
801 |
|
|
gate_input_keystates_t state_keys = extract_state_keys_from_key_state_flags(key_state); |
802 |
|
|
win32_prepare_key_input(&inp, key_code, state_keys, GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_DOWN)); |
803 |
|
|
return win32_send_input(&inp); |
804 |
|
|
} |
805 |
|
|
|
806 |
|
|
|
807 |
|
|
gate_result_t gate_video_screencontrol_create(gate_video_screencontrol_t** ptr_source) |
808 |
|
|
{ |
809 |
|
|
gate_result_t ret = GATE_RESULT_FAILED; |
810 |
|
|
win32screen_t* impl = NULL; |
811 |
|
|
|
812 |
|
|
do |
813 |
|
|
{ |
814 |
|
|
ret = gate_win32_gdi_init(); |
815 |
|
|
GATE_BREAK_IF_FAILED(ret); |
816 |
|
|
|
817 |
|
|
impl = (win32screen_t*)gate_mem_alloc(sizeof(win32screen_t)); |
818 |
|
|
if (impl == NULL) |
819 |
|
|
{ |
820 |
|
|
ret = GATE_RESULT_OUTOFMEMORY; |
821 |
|
|
break; |
822 |
|
|
} |
823 |
|
|
gate_mem_clear(impl, sizeof(win32screen_t)); |
824 |
|
|
impl->vtbl = init_video_screencontrol_vtbl(); |
825 |
|
|
gate_atomic_int_init(&impl->ref_counter, 1); |
826 |
|
|
|
827 |
|
|
if (ptr_source) |
828 |
|
|
{ |
829 |
|
|
*ptr_source = (gate_video_screencontrol_t*)impl; |
830 |
|
|
impl = NULL; |
831 |
|
|
} |
832 |
|
|
ret = GATE_RESULT_OK; |
833 |
|
|
} while (0); |
834 |
|
|
|
835 |
|
|
if (impl != NULL) |
836 |
|
|
{ |
837 |
|
|
screenctrl_release(impl); |
838 |
|
|
} |
839 |
|
|
|
840 |
|
|
return ret; |
841 |
|
|
} |
842 |
|
|
|
843 |
|
|
|
844 |
|
|
#endif |
845 |
|
|
|
846 |
|
|
|
847 |
|
|
#if defined(GATE_IO_VIDEO_X11) |
848 |
|
|
|
849 |
|
|
#include "gate/platform/posix/xlib.h" |
850 |
|
|
#include "gate/debugging.h" |
851 |
|
|
|
852 |
|
|
typedef struct x11screen_class |
853 |
|
|
{ |
854 |
|
|
GATE_INTERFACE_VTBL(gate_video_screencontrol) const* vtbl; |
855 |
|
|
|
856 |
|
|
gate_atomic_int_t ref_counter; |
857 |
|
|
Display* x11_display; |
858 |
|
|
Window x11_root; |
859 |
|
|
gate_video_format_t format; |
860 |
|
|
GC x11_gc; |
861 |
|
|
int x11_screen; |
862 |
|
|
Colormap x11_colmap; |
863 |
|
|
} x11screen_t; |
864 |
|
|
|
865 |
|
|
|
866 |
|
✗ |
static gate_result_t x11screen_init(x11screen_t* self) |
867 |
|
|
{ |
868 |
|
|
gate_result_t result; |
869 |
|
|
|
870 |
|
|
do |
871 |
|
|
{ |
872 |
|
✗ |
result = gate_xlib_load_functions(); |
873 |
|
✗ |
GATE_BREAK_IF_FAILED(result); |
874 |
|
|
|
875 |
|
✗ |
self->x11_display = xlib.XOpenDisplay(NULL); |
876 |
|
✗ |
if (self->x11_display == NULL) |
877 |
|
|
{ |
878 |
|
✗ |
self->x11_display = xlib.XOpenDisplay(":0"); |
879 |
|
|
} |
880 |
|
✗ |
if (self->x11_display == NULL) |
881 |
|
|
{ |
882 |
|
✗ |
GATE_DEBUG_TRACE("Failed to open X11 display"); |
883 |
|
✗ |
result = GATE_RESULT_FAILED; |
884 |
|
✗ |
break; |
885 |
|
|
} |
886 |
|
✗ |
self->x11_root = xlib.XDefaultRootWindow(self->x11_display); |
887 |
|
|
|
888 |
|
|
} while (0); |
889 |
|
|
|
890 |
|
✗ |
return result; |
891 |
|
|
} |
892 |
|
|
|
893 |
|
✗ |
static void x11screen_destroy(x11screen_t* self) |
894 |
|
|
{ |
895 |
|
|
|
896 |
|
✗ |
if (self->x11_display) |
897 |
|
|
{ |
898 |
|
✗ |
xlib.XCloseDisplay(self->x11_display); |
899 |
|
✗ |
self->x11_display = NULL; |
900 |
|
|
} |
901 |
|
✗ |
} |
902 |
|
|
|
903 |
|
|
|
904 |
|
✗ |
static char const* screenctrl_get_interface_name(void* thisptr) |
905 |
|
|
{ |
906 |
|
✗ |
return GATE_INTERFACE_NAME_VIDEO_SOURCE_SCREENCONTROL; |
907 |
|
|
} |
908 |
|
|
|
909 |
|
|
|
910 |
|
✗ |
static void screenctrl_release(void* thisptr) |
911 |
|
|
{ |
912 |
|
✗ |
x11screen_t* const self = (x11screen_t*)thisptr; |
913 |
|
✗ |
if (gate_atomic_int_dec(&self->ref_counter) == 0) |
914 |
|
|
{ |
915 |
|
✗ |
x11screen_destroy(self); |
916 |
|
✗ |
gate_mem_dealloc(self); |
917 |
|
|
} |
918 |
|
✗ |
} |
919 |
|
✗ |
static int screenctrl_retain(void* thisptr) |
920 |
|
|
{ |
921 |
|
✗ |
x11screen_t* const self = (x11screen_t*)thisptr; |
922 |
|
✗ |
return gate_atomic_int_inc(&self->ref_counter); |
923 |
|
|
} |
924 |
|
✗ |
static char const* screenctrl_get_id(void* thisptr) |
925 |
|
|
{ |
926 |
|
✗ |
return "screen"; |
927 |
|
|
} |
928 |
|
✗ |
static char const* screenctrl_get_name(void* thisptr) |
929 |
|
|
{ |
930 |
|
✗ |
return "screen"; |
931 |
|
|
} |
932 |
|
✗ |
static gate_intptr_t screenctrl_get_handle(void* thisptr) |
933 |
|
|
{ |
934 |
|
✗ |
x11screen_t* const self = (x11screen_t*)thisptr; |
935 |
|
✗ |
return (gate_intptr_t)self->x11_display; |
936 |
|
|
} |
937 |
|
✗ |
static gate_size_t screenctrl_get_supported_formats(void* thisptr, gate_video_format_t* format_buffer, gate_size_t format_buffer_count) |
938 |
|
|
{ |
939 |
|
✗ |
x11screen_t* const self = (x11screen_t*)thisptr; |
940 |
|
✗ |
XWindowAttributes attrs = GATE_INIT_EMPTY; |
941 |
|
|
|
942 |
|
✗ |
if ((format_buffer == NULL) || (format_buffer_count < 1)) |
943 |
|
|
{ |
944 |
|
✗ |
GATE_DEBUG_TRACE("Not enough space in output buffer"); |
945 |
|
✗ |
return 0; |
946 |
|
|
} |
947 |
|
|
|
948 |
|
|
/* get screen dimensions */ |
949 |
|
✗ |
xlib.XGetWindowAttributes(self->x11_display, self->x11_root, &attrs); |
950 |
|
|
|
951 |
|
✗ |
format_buffer->encoding_id = 0; |
952 |
|
✗ |
format_buffer->compression = 0; |
953 |
|
✗ |
format_buffer->frames_per_second = 5; |
954 |
|
✗ |
format_buffer->width = (gate_uint32_t)attrs.width; |
955 |
|
✗ |
format_buffer->height = (gate_uint32_t)attrs.height; |
956 |
|
✗ |
format_buffer->bits_per_pixel = 32; |
957 |
|
|
|
958 |
|
✗ |
return 1; /* one entry was used */ |
959 |
|
|
} |
960 |
|
|
|
961 |
|
✗ |
static gate_result_t screenctrl_open(void* thisptr, gate_video_format_t const* format) |
962 |
|
|
{ |
963 |
|
✗ |
x11screen_t* const self = (x11screen_t*)thisptr; |
964 |
|
|
|
965 |
|
✗ |
if (self->x11_gc != NULL) |
966 |
|
|
{ |
967 |
|
✗ |
GATE_DEBUG_TRACE("Error: X11 GC is already initialized"); |
968 |
|
✗ |
return GATE_RESULT_INVALIDSTATE; |
969 |
|
|
} |
970 |
|
|
|
971 |
|
✗ |
gate_mem_copy(&self->format, format, sizeof(gate_video_format_t)); |
972 |
|
|
|
973 |
|
✗ |
self->x11_gc = xlib.XCreateGC(self->x11_display, self->x11_root, 0, NULL); |
974 |
|
✗ |
if (!self->x11_gc) |
975 |
|
|
{ |
976 |
|
✗ |
GATE_DEBUG_TRACE("Error: Failed to create GC on current display"); |
977 |
|
✗ |
return GATE_RESULT_FAILED; |
978 |
|
|
} |
979 |
|
✗ |
self->x11_screen = xlib.XDefaultScreen(self->x11_display); |
980 |
|
✗ |
self->x11_colmap = xlib.XDefaultColormap(self->x11_display, self->x11_screen); |
981 |
|
✗ |
return GATE_RESULT_OK; |
982 |
|
|
} |
983 |
|
✗ |
static gate_result_t screenctrl_close(void* thisptr) |
984 |
|
|
{ |
985 |
|
✗ |
x11screen_t* const self = (x11screen_t*)thisptr; |
986 |
|
|
|
987 |
|
✗ |
if (!self->x11_gc) |
988 |
|
|
{ |
989 |
|
✗ |
xlib.XFreeGC(self->x11_display, self->x11_gc); |
990 |
|
✗ |
self->x11_gc = NULL; |
991 |
|
✗ |
self->x11_screen = 0; |
992 |
|
✗ |
self->x11_colmap = 0; |
993 |
|
|
} |
994 |
|
✗ |
return GATE_RESULT_OK; |
995 |
|
|
} |
996 |
|
|
|
997 |
|
✗ |
static gate_result_t ximage32_to_raster(XImage* ptr_ximage, gate_rasterimage_t* ptr_raster) |
998 |
|
|
{ |
999 |
|
✗ |
unsigned char const* ptr_src_pixel = (unsigned char const*)ptr_ximage->data; |
1000 |
|
|
gate_color_rgb_t* ptr_dst_pixel; |
1001 |
|
|
unsigned int y, x; |
1002 |
|
|
|
1003 |
|
✗ |
if (NULL == gate_rasterimage_create(ptr_raster, GATE_IMAGE_PIXELFORMAT_RGB24, |
1004 |
|
✗ |
(unsigned)ptr_ximage->width, (unsigned)ptr_ximage->height, NULL)) |
1005 |
|
|
{ |
1006 |
|
✗ |
return GATE_RESULT_OUTOFMEMORY; |
1007 |
|
|
} |
1008 |
|
|
|
1009 |
|
✗ |
for (y = 0; y != ptr_raster->height; ++y) |
1010 |
|
|
{ |
1011 |
|
✗ |
ptr_dst_pixel = (gate_color_rgb_t*)gate_rasterimage_get_line_ptr(ptr_raster, y); |
1012 |
|
✗ |
for (x = 0; x != ptr_raster->width; ++x) |
1013 |
|
|
{ |
1014 |
|
✗ |
ptr_dst_pixel->b = *(ptr_src_pixel++); |
1015 |
|
✗ |
ptr_dst_pixel->g = *(ptr_src_pixel++); |
1016 |
|
✗ |
ptr_dst_pixel->r = *(ptr_src_pixel++); |
1017 |
|
✗ |
++ptr_src_pixel; /* skip A value */ |
1018 |
|
✗ |
++ptr_dst_pixel; |
1019 |
|
|
} |
1020 |
|
|
} |
1021 |
|
✗ |
return GATE_RESULT_OK; |
1022 |
|
|
} |
1023 |
|
|
|
1024 |
|
✗ |
static gate_result_t ximage16_to_raster(XImage* ptr_ximage, gate_rasterimage_t* ptr_raster) |
1025 |
|
|
{ |
1026 |
|
✗ |
unsigned char const* ptr_src_pixel = (unsigned char const*)ptr_ximage->data; |
1027 |
|
|
gate_color_rgb_t* ptr_dst_pixel; |
1028 |
|
|
unsigned int y, x; |
1029 |
|
|
|
1030 |
|
✗ |
if (NULL == gate_rasterimage_create(ptr_raster, GATE_IMAGE_PIXELFORMAT_RGB24, |
1031 |
|
✗ |
(unsigned)ptr_ximage->width, (unsigned)ptr_ximage->height, NULL)) |
1032 |
|
|
{ |
1033 |
|
✗ |
return GATE_RESULT_OUTOFMEMORY; |
1034 |
|
|
} |
1035 |
|
|
|
1036 |
|
✗ |
for (y = 0; y != ptr_raster->height; ++y) |
1037 |
|
|
{ |
1038 |
|
✗ |
ptr_dst_pixel = (gate_color_rgb_t*)gate_rasterimage_get_line_ptr(ptr_raster, y); |
1039 |
|
✗ |
for (x = 0; x != ptr_raster->width; ++x) |
1040 |
|
|
{ |
1041 |
|
✗ |
const gate_uint16_t col = (gate_uint16_t)(ptr_src_pixel[0]) | (((gate_uint16_t)ptr_src_pixel[1]) << 8); |
1042 |
|
✗ |
ptr_dst_pixel->b = (gate_uint8_t)((col & 0x001F) << 3); |
1043 |
|
✗ |
ptr_dst_pixel->g = (gate_uint8_t)((col & 0x07e0) >> 3); |
1044 |
|
✗ |
ptr_dst_pixel->r = (gate_uint8_t)((col & 0xF800) >> 8); |
1045 |
|
✗ |
ptr_src_pixel += 2; |
1046 |
|
✗ |
++ptr_dst_pixel; |
1047 |
|
|
} |
1048 |
|
|
} |
1049 |
|
✗ |
return GATE_RESULT_OK; |
1050 |
|
|
} |
1051 |
|
|
|
1052 |
|
✗ |
static gate_result_t ximage_to_raster(Display* display, Colormap colmap, XImage* ptr_ximage, gate_rasterimage_t* ptr_raster) |
1053 |
|
|
{ |
1054 |
|
|
gate_color_rgb_t* ptr_dst_pixel; |
1055 |
|
|
unsigned int y, x; |
1056 |
|
|
XColor xcol; |
1057 |
|
|
|
1058 |
|
✗ |
if (NULL == gate_rasterimage_create(ptr_raster, GATE_IMAGE_PIXELFORMAT_RGB24, |
1059 |
|
✗ |
(unsigned)ptr_ximage->width, (unsigned)ptr_ximage->height, NULL)) |
1060 |
|
|
{ |
1061 |
|
✗ |
return GATE_RESULT_OUTOFMEMORY; |
1062 |
|
|
} |
1063 |
|
|
|
1064 |
|
✗ |
for (y = 0; y != ptr_raster->height; ++y) |
1065 |
|
|
{ |
1066 |
|
✗ |
ptr_dst_pixel = (gate_color_rgb_t*)gate_rasterimage_get_line_ptr(ptr_raster, y); |
1067 |
|
✗ |
for (x = 0; x != ptr_raster->width; ++x) |
1068 |
|
|
{ |
1069 |
|
✗ |
xcol.pixel = xlib.XGetPixel(ptr_ximage, (int)x, (int)y); |
1070 |
|
✗ |
xlib.XQueryColor(display, colmap, &xcol); |
1071 |
|
|
|
1072 |
|
✗ |
ptr_dst_pixel->r = (gate_uint8_t)(xcol.red >> 8); |
1073 |
|
✗ |
ptr_dst_pixel->g = (gate_uint8_t)(xcol.green >> 8); |
1074 |
|
✗ |
ptr_dst_pixel->b = (gate_uint8_t)(xcol.blue >> 8); |
1075 |
|
✗ |
++ptr_dst_pixel; |
1076 |
|
|
} |
1077 |
|
|
} |
1078 |
|
✗ |
return GATE_RESULT_OK; |
1079 |
|
|
} |
1080 |
|
|
|
1081 |
|
✗ |
static gate_result_t screenctrl_read(void* thisptr, gate_video_frame_t* frame) |
1082 |
|
|
{ |
1083 |
|
✗ |
gate_result_t ret = GATE_RESULT_FAILED; |
1084 |
|
✗ |
x11screen_t* const self = (x11screen_t*)thisptr; |
1085 |
|
✗ |
XImage* ptr_ximage = NULL; |
1086 |
|
✗ |
gate_rasterimage_t raster = GATE_INIT_EMPTY; |
1087 |
|
|
|
1088 |
|
|
do |
1089 |
|
|
{ |
1090 |
|
✗ |
ptr_ximage = xlib.XGetImage(self->x11_display, self->x11_root, |
1091 |
|
|
0, 0, self->format.width, self->format.height, AllPlanes, ZPixmap); |
1092 |
|
✗ |
if (ptr_ximage == NULL) |
1093 |
|
|
{ |
1094 |
|
✗ |
ret = GATE_RESULT_FAILED; |
1095 |
|
✗ |
break; |
1096 |
|
|
} |
1097 |
|
|
|
1098 |
|
✗ |
if ((ptr_ximage->bits_per_pixel == 32) && (ptr_ximage->depth == 24)) |
1099 |
|
|
{ |
1100 |
|
✗ |
ret = ximage32_to_raster(ptr_ximage, &raster); |
1101 |
|
|
} |
1102 |
|
✗ |
else if ((ptr_ximage->bits_per_pixel == 16) && (ptr_ximage->depth == 16)) |
1103 |
|
|
{ |
1104 |
|
✗ |
ret = ximage16_to_raster(ptr_ximage, &raster); |
1105 |
|
|
} |
1106 |
|
|
else |
1107 |
|
|
{ |
1108 |
|
✗ |
ret = ximage_to_raster(self->x11_display, self->x11_colmap, ptr_ximage, &raster); |
1109 |
|
|
} |
1110 |
|
|
|
1111 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
1112 |
|
|
|
1113 |
|
✗ |
frame->format.bits_per_pixel = raster.bits_per_pixel; |
1114 |
|
✗ |
frame->format.compression = 0; |
1115 |
|
✗ |
frame->format.encoding_id = 0; |
1116 |
|
✗ |
frame->format.frames_per_second = self->format.frames_per_second; |
1117 |
|
✗ |
frame->format.width = raster.width; |
1118 |
|
✗ |
frame->format.height = raster.height; |
1119 |
|
✗ |
gate_rasterimage_duplicate(&frame->image, &raster); |
1120 |
|
✗ |
frame->record_time = 0; |
1121 |
|
|
|
1122 |
|
✗ |
ret = GATE_RESULT_OK; |
1123 |
|
|
} while (0); |
1124 |
|
|
|
1125 |
|
✗ |
gate_rasterimage_release(&raster); |
1126 |
|
|
|
1127 |
|
✗ |
if (ptr_ximage != NULL) |
1128 |
|
|
{ |
1129 |
|
✗ |
xlib.XDestroyImage(ptr_ximage); |
1130 |
|
|
} |
1131 |
|
|
|
1132 |
|
✗ |
return ret; |
1133 |
|
|
} |
1134 |
|
|
|
1135 |
|
✗ |
static gate_result_t screenctrl_get_cursor_pos(void* thisptr, gate_int32_t* ptr_x, gate_int32_t* ptr_y) |
1136 |
|
|
{ |
1137 |
|
✗ |
gate_result_t ret = GATE_RESULT_FAILED; |
1138 |
|
✗ |
x11screen_t* const self = (x11screen_t*)thisptr; |
1139 |
|
|
Window win, subwin; |
1140 |
|
|
int gx, gy, wx, wy; |
1141 |
|
|
unsigned int state; |
1142 |
|
|
|
1143 |
|
✗ |
if (xlib.XQueryPointer(self->x11_display, self->x11_root, &win, &subwin, &gx, &gy, &wx, &wy, &state)) |
1144 |
|
|
{ |
1145 |
|
✗ |
if (ptr_x) *ptr_x = gx; |
1146 |
|
✗ |
if (ptr_y) *ptr_y = gy; |
1147 |
|
✗ |
return GATE_RESULT_OK; |
1148 |
|
|
} |
1149 |
|
✗ |
return GATE_RESULT_FAILED; |
1150 |
|
|
} |
1151 |
|
|
|
1152 |
|
✗ |
static gate_result_t screenctrl_move_cursor(void* thisptr, gate_int32_t x, gate_int32_t y) |
1153 |
|
|
{ |
1154 |
|
✗ |
gate_result_t ret = GATE_RESULT_FAILED; |
1155 |
|
✗ |
x11screen_t* const self = (x11screen_t*)thisptr; |
1156 |
|
✗ |
xlib.XWarpPointer(self->x11_display, None, self->x11_root, 0, 0, 0, 0, (int)x, (int)y); |
1157 |
|
✗ |
return GATE_RESULT_OK; |
1158 |
|
|
} |
1159 |
|
|
|
1160 |
|
✗ |
static gate_result_t screenctrl_change_cursor_button_state(void* thisptr, gate_int32_t x, gate_int32_t y, gate_enumint_t button_id, gate_enumint_t button_state) |
1161 |
|
|
{ |
1162 |
|
|
/* http://www.linuxquestions.org/questions/programming-9/simulating-a-mouse-click-594576/ */ |
1163 |
|
|
|
1164 |
|
✗ |
gate_result_t ret = GATE_RESULT_FAILED; |
1165 |
|
✗ |
x11screen_t* const self = (x11screen_t*)thisptr; |
1166 |
|
✗ |
XEvent xevt = GATE_INIT_EMPTY; |
1167 |
|
✗ |
XButtonEvent* evt = &xevt.xbutton; |
1168 |
|
|
|
1169 |
|
✗ |
xlib.XWarpPointer(self->x11_display, None, self->x11_root, 0, 0, 0, 0, (int)x, (int)y); |
1170 |
|
|
|
1171 |
|
|
/* find inner sub-window */ |
1172 |
|
✗ |
evt->type = (button_state == GATE_VIDEO_SCREENCONTROL_STATE_DOWN) ? ButtonPress : ButtonRelease; |
1173 |
|
✗ |
evt->display = self->x11_display; |
1174 |
|
✗ |
evt->same_screen = True; |
1175 |
|
✗ |
evt->time = CurrentTime; |
1176 |
|
|
|
1177 |
|
✗ |
evt->subwindow = self->x11_root; |
1178 |
|
|
do |
1179 |
|
|
{ |
1180 |
|
✗ |
evt->window = evt->subwindow; |
1181 |
|
✗ |
xlib.XQueryPointer(self->x11_display, evt->window, &evt->root, &evt->subwindow, &evt->x_root, &evt->y_root, &evt->x, &evt->y, &evt->state); |
1182 |
|
✗ |
} while (evt->subwindow != 0); |
1183 |
|
|
|
1184 |
|
|
|
1185 |
|
|
|
1186 |
|
✗ |
evt->state = 0; |
1187 |
|
✗ |
if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_LEFT) |
1188 |
|
|
{ |
1189 |
|
✗ |
evt->button = Button1; |
1190 |
|
✗ |
evt->state |= Button1Mask; |
1191 |
|
|
} |
1192 |
|
✗ |
else if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_MIDDLE) |
1193 |
|
|
{ |
1194 |
|
✗ |
evt->button = Button2; |
1195 |
|
✗ |
evt->state |= Button2Mask; |
1196 |
|
|
} |
1197 |
|
✗ |
else if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_RIGHT) |
1198 |
|
|
{ |
1199 |
|
✗ |
evt->button = Button3; |
1200 |
|
✗ |
evt->state |= Button3Mask; |
1201 |
|
|
} |
1202 |
|
|
|
1203 |
|
✗ |
xlib.XSendEvent(self->x11_display, PointerWindow, True, 0xfff, &xevt); |
1204 |
|
✗ |
xlib.XFlush(self->x11_display); |
1205 |
|
|
|
1206 |
|
✗ |
return GATE_RESULT_OK; |
1207 |
|
|
} |
1208 |
|
|
|
1209 |
|
✗ |
static gate_result_t screenctrl_change_key_state(void* thisptr, gate_input_keycode_t key_code, gate_enumint_t key_state) |
1210 |
|
|
{ |
1211 |
|
✗ |
gate_result_t ret = GATE_RESULT_FAILED; |
1212 |
|
✗ |
x11screen_t* const self = (x11screen_t*)thisptr; |
1213 |
|
|
XKeyEvent evt; |
1214 |
|
|
int focus_state; |
1215 |
|
✗ |
Window focus_win = self->x11_root; |
1216 |
|
✗ |
KeySym x11_key_sym = key_code; |
1217 |
|
✗ |
gate_bool_t key_down = GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_DOWN); |
1218 |
|
✗ |
unsigned int x11_state = 0; |
1219 |
|
|
|
1220 |
|
✗ |
if (key_down && GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_CTRL)) |
1221 |
|
|
{ |
1222 |
|
✗ |
x11_state |= ControlMask; |
1223 |
|
|
} |
1224 |
|
✗ |
if (key_down && GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_MENU)) |
1225 |
|
|
{ |
1226 |
|
✗ |
x11_state |= Mod1Mask; |
1227 |
|
|
} |
1228 |
|
✗ |
if (key_down && GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_SHIFT)) |
1229 |
|
|
{ |
1230 |
|
✗ |
x11_state |= ShiftMask; |
1231 |
|
|
} |
1232 |
|
|
|
1233 |
|
✗ |
xlib.XGetInputFocus(self->x11_display, &focus_win, &focus_state); |
1234 |
|
|
|
1235 |
|
✗ |
evt.display = self->x11_display; |
1236 |
|
✗ |
evt.window = focus_win; |
1237 |
|
✗ |
evt.root = self->x11_root; |
1238 |
|
✗ |
evt.subwindow = None; |
1239 |
|
✗ |
evt.time = CurrentTime; |
1240 |
|
✗ |
evt.x = 1; |
1241 |
|
✗ |
evt.y = 1; |
1242 |
|
✗ |
evt.x_root = 1; |
1243 |
|
✗ |
evt.y_root = 1; |
1244 |
|
✗ |
evt.same_screen = True; |
1245 |
|
✗ |
evt.send_event = True; |
1246 |
|
✗ |
evt.keycode = xlib.XKeysymToKeycode(self->x11_display, x11_key_sym); |
1247 |
|
✗ |
evt.state = x11_state; |
1248 |
|
✗ |
evt.type = key_down ? KeyPress : KeyRelease; |
1249 |
|
✗ |
xlib.XSendEvent(evt.display, evt.window, True, KeyPressMask, (XEvent*)&evt); |
1250 |
|
|
|
1251 |
|
✗ |
return GATE_RESULT_OK; |
1252 |
|
|
} |
1253 |
|
|
|
1254 |
|
|
|
1255 |
|
|
|
1256 |
|
✗ |
gate_result_t gate_video_screencontrol_create(gate_video_screencontrol_t** ptr_source) |
1257 |
|
|
{ |
1258 |
|
✗ |
gate_result_t ret = GATE_RESULT_FAILED; |
1259 |
|
✗ |
x11screen_t* impl = NULL; |
1260 |
|
|
|
1261 |
|
|
do |
1262 |
|
|
{ |
1263 |
|
✗ |
impl = (x11screen_t*)gate_mem_alloc(sizeof(x11screen_t)); |
1264 |
|
✗ |
if (impl == NULL) |
1265 |
|
|
{ |
1266 |
|
✗ |
ret = GATE_RESULT_OUTOFMEMORY; |
1267 |
|
✗ |
break; |
1268 |
|
|
} |
1269 |
|
✗ |
gate_mem_clear(impl, sizeof(x11screen_t)); |
1270 |
|
✗ |
impl->vtbl = init_video_screencontrol_vtbl(); |
1271 |
|
✗ |
gate_atomic_int_init(&impl->ref_counter, 1); |
1272 |
|
|
|
1273 |
|
✗ |
ret = x11screen_init(impl); |
1274 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
1275 |
|
|
|
1276 |
|
✗ |
if (ptr_source) |
1277 |
|
|
{ |
1278 |
|
✗ |
*ptr_source = (gate_video_screencontrol_t*)impl; |
1279 |
|
✗ |
impl = NULL; |
1280 |
|
|
} |
1281 |
|
✗ |
ret = GATE_RESULT_OK; |
1282 |
|
|
} while (0); |
1283 |
|
|
|
1284 |
|
✗ |
if (impl != NULL) |
1285 |
|
|
{ |
1286 |
|
✗ |
screenctrl_release(impl); |
1287 |
|
|
} |
1288 |
|
|
|
1289 |
|
✗ |
return ret; |
1290 |
|
|
} |
1291 |
|
|
|
1292 |
|
|
#endif |
1293 |
|
|
|
1294 |
|
|
#if defined(GATE_IO_VIDEO_ANDROID) |
1295 |
|
|
|
1296 |
|
|
gate_result_t gate_video_screencontrol_create(gate_video_screencontrol_t** ptr_source) |
1297 |
|
|
{ |
1298 |
|
|
GATE_UNUSED_ARG(ptr_source); |
1299 |
|
|
/* TODO */ |
1300 |
|
|
return GATE_RESULT_NOTSUPPORTED; |
1301 |
|
|
} |
1302 |
|
|
|
1303 |
|
|
#endif |
1304 |
|
|
|
1305 |
|
|
|
1306 |
|
|
#if defined(GATE_IO_VIDEO_NO_IMPL) |
1307 |
|
|
|
1308 |
|
|
gate_result_t gate_video_screencontrol_create(gate_video_screencontrol_t** ptr_source) |
1309 |
|
|
{ |
1310 |
|
|
GATE_UNUSED_ARG(ptr_source); |
1311 |
|
|
return GATE_RESULT_NOTSUPPORTED; |
1312 |
|
|
} |
1313 |
|
|
|
1314 |
|
|
#endif |
1315 |
|
|
|